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:
authorBenoit Bolsee <benoit.bolsee@online.be>2016-05-18 23:56:31 +0300
committerBenoit Bolsee <benoit.bolsee@online.be>2016-05-18 23:56:31 +0300
commitad2bf24a19084360babf3db09197499bfaaa251a (patch)
tree386d190767db8c0c66fa09917b926d72ab675d1a /source/blender
parentb8435f48f02e3fdd69bfba68c2a890bd3340b085 (diff)
parent6988061bf1258fe583ea2d95bc26572477709868 (diff)
Merge remote-tracking branch 'origin/master' into decklink
Conflicts: intern/atomic/atomic_ops.h
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenfont/BLF_api.h4
-rw-r--r--source/blender/blenfont/intern/blf.c11
-rw-r--r--source/blender/blenfont/intern/blf_font.c2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h26
-rw-r--r--source/blender/blenkernel/BKE_action.h11
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender.h82
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h46
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h52
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h44
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h67
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h77
-rw-r--r--source/blender/blenkernel/BKE_cloth.h2
-rw-r--r--source/blender/blenkernel/BKE_customdata.h4
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h6
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_mask.h6
-rw-r--r--source/blender/blenkernel/BKE_mesh.h7
-rw-r--r--source/blender/blenkernel/BKE_modifier.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/BKE_sketch.h1
-rw-r--r--source/blender/blenkernel/BKE_unit.h10
-rw-r--r--source/blender/blenkernel/CMakeLists.txt9
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c417
-rw-r--r--source/blender/blenkernel/intern/action.c63
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c210
-rw-r--r--source/blender/blenkernel/intern/armature_update.c14
-rw-r--r--source/blender/blenkernel/intern/blender.c977
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c143
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c393
-rw-r--r--source/blender/blenkernel/intern/blendfile.c569
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c702
-rw-r--r--source/blender/blenkernel/intern/camera.c4
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c24
-rw-r--r--source/blender/blenkernel/intern/cloth.c124
-rw-r--r--source/blender/blenkernel/intern/collision.c10
-rw-r--r--source/blender/blenkernel/intern/constraint.c79
-rw-r--r--source/blender/blenkernel/intern/curve.c20
-rw-r--r--source/blender/blenkernel/intern/customdata.c56
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c11
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c35
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c1034
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c235
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c2
-rw-r--r--source/blender/blenkernel/intern/effect.c12
-rw-r--r--source/blender/blenkernel/intern/fcurve.c49
-rw-r--r--source/blender/blenkernel/intern/font.c5
-rw-r--r--source/blender/blenkernel/intern/gpencil.c10
-rw-r--r--source/blender/blenkernel/intern/image.c65
-rw-r--r--source/blender/blenkernel/intern/image_gen.c268
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/library.c15
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/material.c17
-rw-r--r--source/blender/blenkernel/intern/mesh.c7
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c40
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/object.c5
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c7
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c100
-rw-r--r--source/blender/blenkernel/intern/pbvh.c11
-rw-r--r--source/blender/blenkernel/intern/pointcache.c1
-rw-r--r--source/blender/blenkernel/intern/scene.c15
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c14
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c91
-rw-r--r--source/blender/blenkernel/intern/sketch.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c30
-rw-r--r--source/blender/blenkernel/intern/unit.c83
-rw-r--r--source/blender/blenlib/BLI_array_utils.h12
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h12
-rw-r--r--source/blender/blenlib/BLI_math_base.h10
-rw-r--r--source/blender/blenlib/BLI_math_geom.h6
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h3
-rw-r--r--source/blender/blenlib/BLI_math_vector.h7
-rw-r--r--source/blender/blenlib/BLI_task.h30
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c57
-rw-r--r--source/blender/blenlib/intern/array_utils.c126
-rw-r--r--source/blender/blenlib/intern/graph.c2
-rw-r--r--source/blender/blenlib/intern/math_base.c2
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c99
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c68
-rw-r--r--source/blender/blenlib/intern/math_geom.c24
-rw-r--r--source/blender/blenlib/intern/math_matrix.c15
-rw-r--r--source/blender/blenlib/intern/math_vector.c55
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c15
-rw-r--r--source/blender/blenlib/intern/path_util.c6
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c22
-rw-r--r--source/blender/blenlib/intern/scanfill.c22
-rw-r--r--source/blender/blenlib/intern/task.c440
-rw-r--r--source/blender/blenloader/intern/readfile.c24
-rw-r--r--source/blender/blenloader/intern/versioning_270.c128
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/blentranslation/BLT_translation.h1
-rw-r--r--source/blender/blentranslation/CMakeLists.txt6
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c59
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c81
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h23
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c11
-rw-r--r--source/blender/bmesh/intern/bmesh_queries_inline.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c77
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c44
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c22
-rw-r--r--source/blender/bmesh/operators/bmo_mesh_conv.c7
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c20
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c175
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c21
-rw-r--r--source/blender/collada/DocumentExporter.cpp2
-rw-r--r--source/blender/collada/MeshImporter.cpp1
-rw-r--r--source/blender/collada/collada.cpp5
-rw-r--r--source/blender/collada/collada_utils.cpp7
-rw-r--r--source/blender/compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cpp7
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp24
-rw-r--r--source/blender/depsgraph/CMakeLists.txt4
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc22
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc26
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_nodes.cc23
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc9
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc265
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc67
-rw-r--r--source/blender/depsgraph/intern/depsnode.cc13
-rw-r--r--source/blender/depsgraph/intern/depsnode.h2
-rw-r--r--source/blender/editors/animation/CMakeLists.txt4
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c3
-rw-r--r--source/blender/editors/animation/anim_markers.c10
-rw-r--r--source/blender/editors/animation/drivers.c126
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c5
-rw-r--r--source/blender/editors/armature/armature_add.c34
-rw-r--r--source/blender/editors/armature/armature_intern.h5
-rw-r--r--source/blender/editors/armature/armature_utils.c24
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c9
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c124
-rw-r--r--source/blender/editors/armature/pose_lib.c14
-rw-r--r--source/blender/editors/armature/pose_slide.c27
-rw-r--r--source/blender/editors/armature/pose_transform.c28
-rw-r--r--source/blender/editors/armature/pose_utils.c25
-rw-r--r--source/blender/editors/curve/CMakeLists.txt8
-rw-r--r--source/blender/editors/curve/curve_intern.h4
-rw-r--r--source/blender/editors/curve/curve_ops.c13
-rw-r--r--source/blender/editors/curve/editcurve.c150
-rw-r--r--source/blender/editors/curve/editcurve_paint.c1234
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c219
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h2
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c71
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c120
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c22
-rw-r--r--source/blender/editors/include/BIF_glutil.h18
-rw-r--r--source/blender/editors/include/ED_anim_api.h4
-rw-r--r--source/blender/editors/include/ED_armature.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h19
-rw-r--r--source/blender/editors/include/ED_mesh.h2
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_transform.h53
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h140
-rw-r--r--source/blender/editors/include/ED_view3d.h12
-rw-r--r--source/blender/editors/include/UI_icons.h22
-rw-r--r--source/blender/editors/interface/interface_anim.c14
-rw-r--r--source/blender/editors/interface/interface_handlers.c65
-rw-r--r--source/blender/editors/interface/interface_icons.c80
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_regions.c28
-rw-r--r--source/blender/editors/interface/interface_style.c6
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/interface/interface_widgets.c24
-rw-r--r--source/blender/editors/interface/resources.c20
-rw-r--r--source/blender/editors/mask/mask_add.c89
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c42
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c28
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c18
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c99
-rw-r--r--source/blender/editors/mesh/editmesh_path.c15
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.c47
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c55
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c16
-rw-r--r--source/blender/editors/mesh/mesh_data.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c12
-rw-r--r--source/blender/editors/object/object_bake.c6
-rw-r--r--source/blender/editors/object/object_edit.c27
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_vgroup.c55
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c3
-rw-r--r--source/blender/editors/physics/particle_edit.c116
-rw-r--r--source/blender/editors/physics/physics_intern.h2
-rw-r--r--source/blender/editors/physics/physics_ops.c2
-rw-r--r--source/blender/editors/render/render_internal.c3
-rw-r--r--source/blender/editors/screen/area.c14
-rw-r--r--source/blender/editors/screen/glutil.c113
-rw-r--r--source/blender/editors/screen/screen_edit.c14
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c25
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c128
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c7
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_action/action_buttons.c132
-rw-r--r--source/blender/editors/space_action/action_edit.c31
-rw-r--r--source/blender/editors/space_action/action_intern.h10
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/space_action.c99
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c111
-rw-r--r--source/blender/editors/space_graph/graph_edit.c222
-rw-r--r--source/blender/editors/space_graph/graph_intern.h7
-rw-r--r--source/blender/editors/space_graph/graph_ops.c10
-rw-r--r--source/blender/editors/space_graph/graph_select.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_image/image_draw.c20
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c151
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_edit.c88
-rw-r--r--source/blender/editors/space_nla/nla_intern.h1
-rw-r--r--source/blender/editors/space_nla/nla_ops.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c1
-rw-r--r--source/blender/editors/space_node/node_relationships.c8
-rw-r--r--source/blender/editors/space_node/node_templates.c36
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c34
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h10
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c62
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c33
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_text/space_text.c10
-rw-r--r--source/blender/editors/space_text/text_draw.c2
-rw-r--r--source/blender/editors/space_time/time_ops.c38
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c102
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c13
-rw-r--r--source/blender/editors/space_view3d/drawobject.c250
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c134
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h4
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c35
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c79
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c53
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c53
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.c237
-rw-r--r--source/blender/editors/transform/transform.h11
-rw-r--r--source/blender/editors/transform/transform_constraints.c6
-rw-r--r--source/blender/editors/transform/transform_conversions.c10
-rw-r--r--source/blender/editors/transform/transform_generics.c15
-rw-r--r--source/blender/editors/transform/transform_snap.c1338
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1767
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/editmode_undo.c2
-rw-r--r--source/blender/editors/util/undo.c15
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c9
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp8
-rw-r--r--source/blender/freestyle/intern/application/Controller.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp14
-rw-r--r--source/blender/freestyle/intern/system/PseudoNoise.cpp2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c8
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c7
-rw-r--r--source/blender/gpu/intern/gpu_draw.c76
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl18
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h10
-rw-r--r--source/blender/imbuf/IMB_imbuf.h28
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c81
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c183
-rw-r--r--source/blender/imbuf/intern/divers.c157
-rw-r--r--source/blender/imbuf/intern/imageprocess.c54
-rw-r--r--source/blender/imbuf/intern/jp2.c6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp53
-rw-r--r--source/blender/imbuf/intern/rectop.c63
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c3
-rw-r--r--source/blender/makesdna/DNA_action_types.h46
-rw-r--r--source/blender/makesdna/DNA_armature_types.h14
-rw-r--r--source/blender/makesdna/DNA_camera_types.h5
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h4
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h19
-rw-r--r--source/blender/makesdna/DNA_material_types.h5
-rw-r--r--source/blender/makesdna/DNA_node_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h37
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h1
-rw-r--r--source/blender/makesdna/intern/makesdna.c37
-rw-r--r--source/blender/makesrna/RNA_types.h14
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c2
-rw-r--r--source/blender/makesrna/intern/rna_armature.c78
-rw-r--r--source/blender/makesrna/intern/rna_brush.c20
-rw-r--r--source/blender/makesrna/intern/rna_camera.c22
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c1
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c55
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c123
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c29
-rw-r--r--source/blender/makesrna/intern/rna_internal.h3
-rw-r--r--source/blender/makesrna/intern/rna_nla.c62
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c6
-rw-r--r--source/blender/makesrna/intern/rna_object.c8
-rw-r--r--source/blender/makesrna/intern/rna_pose.c88
-rw-r--r--source/blender/makesrna/intern/rna_scene.c110
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c22
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c10
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c59
-rw-r--r--source/blender/makesrna/intern/rna_texture.c28
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c4
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/makesrna/intern/rna_wm.c1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c1
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c1
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c8
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c1
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c1
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c6
-rw-r--r--source/blender/nodes/shader/node_shader_util.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c17
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c110
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.c2
-rw-r--r--source/blender/nodes/texture/node_texture_util.h1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp2
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c13
-rw-r--r--source/blender/python/generic/blf_py_api.c10
-rw-r--r--source/blender/python/generic/py_capi_utils.c4
-rw-r--r--source/blender/python/intern/bpy.c2
-rw-r--r--source/blender/python/intern/bpy_app.c2
-rw-r--r--source/blender/python/intern/bpy_driver.c18
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_library_write.c17
-rw-r--r--source/blender/python/intern/bpy_props.c2
-rw-r--r--source/blender/python/intern/bpy_rna.c12
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c17
-rw-r--r--source/blender/python/intern/bpy_util.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c8
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/render_types.h2
-rw-r--r--source/blender/render/intern/include/renderdatabase.h4
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp4
-rw-r--r--source/blender/render/intern/source/bake.c2
-rw-r--r--source/blender/render/intern/source/bake_api.c2
-rw-r--r--source/blender/render/intern/source/convertblender.c60
-rw-r--r--source/blender/render/intern/source/multires_bake.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/render/intern/source/rayshade.c4
-rw-r--r--source/blender/render/intern/source/renderdatabase.c41
-rw-r--r--source/blender/render/intern/source/shadeinput.c37
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c46
-rw-r--r--source/blender/windowmanager/intern/wm_files.c853
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c520
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c29
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c1053
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c6
-rw-r--r--source/blender/windowmanager/wm_cursors.h2
-rw-r--r--source/blender/windowmanager/wm_event_types.h1
-rw-r--r--source/blender/windowmanager/wm_files.h28
403 files changed, 15484 insertions, 7311 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index e565ffe3cc1..1f38d64924c 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -153,7 +153,7 @@ void BLF_disable(int fontid, int option);
* the other argument are the rgba color.
* Take care that shadow need to be enable using BLF_enable!!!
*/
-void BLF_shadow(int fontid, int level, float r, float g, float b, float a);
+void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3);
/* Set the offset for shadow text, this is the current cursor
* position plus this offset, don't need call BLF_position before
@@ -174,7 +174,7 @@ void BLF_shadow_offset(int fontid, int x, int y);
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int nch, struct ColorManagedDisplay *display);
/* Set the color to be used for text. */
-void BLF_buffer_col(int fontid, float r, float g, float b, float a);
+void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2);
/* Draw the string into the buffer, this function draw in both buffer, float and unsigned char _BUT_
* it's not necessary set both buffer, NULL is valid here.
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 977fa771014..132a0ec3808 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -849,16 +849,13 @@ void BLF_wordwrap(int fontid, int wrap_width)
}
}
-void BLF_shadow(int fontid, int level, float r, float g, float b, float a)
+void BLF_shadow(int fontid, int level, const float rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
font->shadow = level;
- font->shadow_col[0] = r;
- font->shadow_col[1] = g;
- font->shadow_col[2] = b;
- font->shadow_col[3] = a;
+ copy_v4_v4(font->shadow_col, rgba);
}
}
@@ -886,12 +883,12 @@ void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int
}
}
-void BLF_buffer_col(int fontid, float r, float g, float b, float a)
+void BLF_buffer_col(int fontid, const float rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
- ARRAY_SET_ITEMS(font->buf_info.col_init, r, g, b, a);
+ copy_v4_v4(font->buf_info.col_init, rgba);
}
}
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 7c6bef57aa4..dfebaecb96e 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -411,7 +411,7 @@ static void blf_font_draw_buffer_ex(
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
- cbuf[3] = (unsigned char)((alphatest = ((int)cbuf[3] + (int)(a * 255)) < 255) ?
+ cbuf[3] = (unsigned char)(((alphatest = ((int)cbuf[3] + (int)(a * 255))) < 255) ?
alphatest : 255);
}
}
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index d7d6daa7e2a..2b13a847e14 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -71,6 +71,7 @@
* as it is and stick with using BMesh and CDDM.
*/
+#include "DNA_defs.h"
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
@@ -180,7 +181,7 @@ struct DerivedMesh {
int numVertData, numEdgeData, numTessFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
- BVHCache bvhCache;
+ BVHCache *bvhCache;
struct GPUDrawObject *drawObject;
DerivedMeshType type;
float auto_bump_scale;
@@ -200,6 +201,8 @@ struct DerivedMesh {
/* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
char cd_flag;
+ char tangent_mask; /* which tangent layers are calculated */
+
/** Calculate vert and face normals */
void (*calcNormals)(DerivedMesh *dm);
@@ -210,7 +213,9 @@ struct DerivedMesh {
void (*calcLoopNormalsSpaceArray)(DerivedMesh *dm, const bool use_split_normals, const float split_angle,
struct MLoopNorSpaceArray *r_lnors_spacearr);
- void (*calcLoopTangents)(DerivedMesh *dm);
+ void (*calcLoopTangents)(
+ DerivedMesh *dm, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count);
/** Recalculates mesh tessellation */
void (*recalcTessellation)(DerivedMesh *dm);
@@ -763,7 +768,7 @@ typedef struct DMVertexAttribs {
struct {
float (*array)[4];
int em_offset, gl_index;
- } tang;
+ } tang[MAX_MTFACE];
struct {
float (*array)[3];
@@ -779,7 +784,20 @@ void DM_vertex_attributes_from_gpu(
void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
-void DM_calc_loop_tangents(DerivedMesh *dm);
+void DM_calc_tangents_names_from_gpu(
+ const struct GPUVertexAttribs *gattribs,
+ char (*tangent_names)[MAX_NAME], int *tangent_names_count);
+void DM_add_named_tangent_layer_for_uv(
+ CustomData *uv_data, CustomData *tan_data, int numLoopData,
+ const char *layer_name);
+void DM_calc_loop_tangents_step_0(
+ const CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
+void DM_calc_loop_tangents(
+ DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
+ int tangent_names_count);
void DM_calc_auto_bump_scale(DerivedMesh *dm);
/** Set object's bounding box based on DerivedMesh min/max data */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 3fceef5d95d..cb282b46bec 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,12 +79,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1 << 1),
/* scaling */
ACT_TRANS_SCALE = (1 << 2),
-
+
+ /* bbone shape - for all the parameters, provided one is set */
+ ACT_TRANS_BBONE = (1 << 3),
+
/* strictly not a transform, but custom properties are also
* quite often used in modern rigs
*/
- ACT_TRANS_PROP = (1 << 3),
-
+ ACT_TRANS_PROP = (1 << 4),
+
/* all flags */
ACT_TRANS_ONLY = (ACT_TRANS_LOC | ACT_TRANS_ROT | ACT_TRANS_SCALE),
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP)
@@ -144,6 +147,8 @@ void BKE_pose_channels_remove(
struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data);
+void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
+void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_copy_data(struct bPose **dst, struct bPose *src, const bool copy_constraints);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 6d00110e318..cc082c084ce 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -135,6 +135,7 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
+void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index fdb34743f36..8ce85c8e615 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -38,88 +38,20 @@
extern "C" {
#endif
-/* these lines are grep'd, watch out for our not-so-awesome regex
- * and keep comment above the defines.
- * Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 277
-#define BLENDER_SUBVERSION 0
-/* Several breakages with 270, e.g. constraint deg vs rad */
-#define BLENDER_MINVERSION 270
-#define BLENDER_MINSUBVERSION 6
+void BKE_blender_free(void);
-/* used by packaging tools */
-/* can be left blank, otherwise a,b,c... etc with no quotes */
-#define BLENDER_VERSION_CHAR
-/* alpha/beta/rc/release, docs use this */
-#define BLENDER_VERSION_CYCLE alpha
+void BKE_blender_globals_init(void);
+void BKE_blender_globals_clear(void);
-extern char versionstr[]; /* from blender.c */
-
-struct MemFile;
-struct bContext;
-struct ReportList;
-struct Scene;
-struct Main;
-struct ID;
-
-int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *reports);
-
-#define BKE_READ_FILE_FAIL 0 /* no load */
-#define BKE_READ_FILE_OK 1 /* OK */
-#define BKE_READ_FILE_OK_USERPREFS 2 /* OK, and with new user settings */
-
-bool BKE_read_file_from_memory(
- struct bContext *C, const void *filebuf,
- int filelength, struct ReportList *reports, bool update_defaults);
-bool BKE_read_file_from_memfile(
- struct bContext *C, struct MemFile *memfile,
- struct ReportList *reports);
-
-int BKE_read_file_userdef(const char *filepath, struct ReportList *reports);
-int BKE_write_file_userdef(const char *filepath, struct ReportList *reports);
-
-void free_blender(void);
-void initglobals(void);
-
-/* load new userdef from file, exit blender */
-void BKE_userdef_free(void);
-/* handle changes in userdef */
-void BKE_userdef_state(void);
+void BKE_blender_userdef_free(void);
+void BKE_blender_userdef_refresh(void);
/* set this callback when a UI is running */
void BKE_blender_callback_test_break_set(void (*func)(void));
-int blender_test_break(void);
-
-#define BKE_UNDO_STR_MAX 64
-
-/* global undo */
-extern void BKE_undo_write(struct bContext *C, const char *name);
-extern void BKE_undo_step(struct bContext *C, int step);
-extern void BKE_undo_name(struct bContext *C, const char *name);
-extern bool BKE_undo_is_valid(const char *name);
-extern void BKE_undo_reset(void);
-extern void BKE_undo_number(struct bContext *C, int nr);
-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);
-
-/* partial blend file writing */
-void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
-void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
-bool BKE_blendfile_write_partial(
- struct Main *bmain_src, const char *filepath, const int write_flags, struct ReportList *reports);
-void BKE_blendfile_write_partial_end(struct Main *bmain_src);
-
-
-/* copybuffer (wrapper for BKE_blendfile_write_partial) */
-void BKE_copybuffer_begin(struct Main *bmain_src);
-void BKE_copybuffer_tag_ID(struct ID *id);
-bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
-bool BKE_copybuffer_paste(struct bContext *C, const char *libname, const short flag, struct ReportList *reports);
+int BKE_blender_test_break(void);
#ifdef __cplusplus
}
#endif
-#endif
-
+#endif /* __BKE_BLENDER_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
new file mode 100644
index 00000000000..8aaf295c33a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_BLENDER_COPYBUFFER_H__
+#define __BKE_BLENDER_COPYBUFFER_H__
+
+/** \file BKE_blender_copybuffer.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct ReportList;
+struct Main;
+struct ID;
+
+/* copybuffer (wrapper for BKE_blendfile_write_partial) */
+void BKE_copybuffer_begin(struct Main *bmain_src);
+void BKE_copybuffer_tag_ID(struct ID *id);
+bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
+bool BKE_copybuffer_paste(struct bContext *C, const char *libname, const short flag, struct ReportList *reports);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_BLENDER_COPYBUFFER_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
new file mode 100644
index 00000000000..cd18bd8db40
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_BLENDER_UNDO_H__
+#define __BKE_BLENDER_UNDO_H__
+
+/** \file BKE_blender_undo.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct Scene;
+struct Main;
+
+#define BKE_UNDO_STR_MAX 64
+
+/* global undo */
+extern void BKE_undo_write(struct bContext *C, const char *name);
+extern void BKE_undo_step(struct bContext *C, int step);
+extern void BKE_undo_name(struct bContext *C, const char *name);
+extern bool BKE_undo_is_valid(const char *name);
+extern void BKE_undo_reset(void);
+extern void BKE_undo_number(struct bContext *C, int nr);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_BLENDER_UNDO_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
new file mode 100644
index 00000000000..618b36c5851
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -0,0 +1,44 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_BLENDER_VERSION_H__
+#define __BKE_BLENDER_VERSION_H__
+
+/** \file BKE_blender_version.h
+ * \ingroup bke
+ */
+
+/* these lines are grep'd, watch out for our not-so-awesome regex
+ * and keep comment above the defines.
+ * Use STRINGIFY() rather than defining with quotes */
+#define BLENDER_VERSION 277
+#define BLENDER_SUBVERSION 1
+/* Several breakages with 270, e.g. constraint deg vs rad */
+#define BLENDER_MINVERSION 270
+#define BLENDER_MINSUBVERSION 6
+
+/* used by packaging tools */
+/* can be left blank, otherwise a,b,c... etc with no quotes */
+#define BLENDER_VERSION_CHAR
+/* alpha/beta/rc/release, docs use this */
+#define BLENDER_VERSION_CYCLE alpha
+
+extern char versionstr[]; /* from blender.c */
+
+#endif /* __BKE_BLENDER_VERSION_H__ */
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
new file mode 100644
index 00000000000..6767fce3abd
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_BLENDFILE_H__
+#define __BKE_BLENDFILE_H__
+
+/** \file BKE_blendfile.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct ID;
+struct Main;
+struct MemFile;
+struct ReportList;
+
+int BKE_blendfile_read(struct bContext *C, const char *filepath, struct ReportList *reports);
+
+enum {
+ BKE_BLENDFILE_READ_FAIL = 0, /* no load */
+ BKE_BLENDFILE_READ_OK = 1, /* OK */
+ BKE_BLENDFILE_READ_OK_USERPREFS = 2, /* OK, and with new user settings */
+};
+
+bool BKE_blendfile_read_from_memory(
+ struct bContext *C, const void *filebuf,
+ int filelength, struct ReportList *reports, bool update_defaults);
+bool BKE_blendfile_read_from_memfile(
+ struct bContext *C, struct MemFile *memfile,
+ struct ReportList *reports);
+
+int BKE_blendfile_read_userdef(const char *filepath, struct ReportList *reports);
+int BKE_blendfile_write_userdef(const char *filepath, struct ReportList *reports);
+
+
+/* partial blend file writing */
+void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
+void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
+bool BKE_blendfile_write_partial(
+ struct Main *bmain_src, const char *filepath, const int write_flags, struct ReportList *reports);
+void BKE_blendfile_write_partial_end(struct Main *bmain_src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_BLENDFILE_H__ */
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 08c0fcc0f3c..7bd3ca88076 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -39,10 +39,30 @@
*/
struct DerivedMesh;
+struct BMEditMesh;
struct MVert;
struct MFace;
/**
+* struct that kepts basic information about a BVHTree build from a editmesh
+*/
+typedef struct BVHTreeFromEditMesh {
+ struct BVHTree *tree;
+
+ /* default callbacks to bvh nearest and raycast */
+ BVHTree_NearestPointCallback nearest_callback;
+ BVHTree_RayCastCallback raycast_callback;
+ BVHTree_NearestToRayCallback nearest_to_ray_callback;
+
+ /* radius for raycast */
+ float sphere_radius;
+
+ /* Private data */
+ struct BMEditMesh *em;
+
+} BVHTreeFromEditMesh;
+
+/**
* struct that kepts basic information about a BVHTree build from a mesh
*/
typedef struct BVHTreeFromMesh {
@@ -69,8 +89,6 @@ typedef struct BVHTreeFromMesh {
float sphere_radius;
/* Private data */
- void *em_evil;
- bool em_evil_all; /* ignore selection/hidden state, adding all loops to the tree */
bool cached;
} BVHTreeFromMesh;
@@ -85,11 +103,19 @@ typedef struct BVHTreeFromMesh {
*
* free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
+BVHTree *bvhtree_from_editmesh_verts(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_verts_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *mask, int verts_num_active,
+ float epsilon, int tree_type, int axis);
+
BVHTree *bvhtree_from_mesh_verts(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_verts_ex(
struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts,
- const bool vert_allocated, BLI_bitmap *mask, int numVerts_active,
+ const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_edges(
@@ -103,7 +129,15 @@ BVHTree *bvhtree_from_mesh_faces_ex(
struct BVHTreeFromMesh *data,
struct MVert *vert, const bool vert_allocated,
struct MFace *face, const int numFaces, const bool face_allocated,
- BLI_bitmap *mask, int numFaces_active,
+ const BLI_bitmap *mask, int numFaces_active,
+ float epsilon, int tree_type, int axis);
+
+BVHTree *bvhtree_from_editmesh_looptri(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon,
+ int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_looptri_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_looptri(
@@ -113,12 +147,13 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const struct MVert *vert, const bool vert_allocated,
const struct MLoop *mloop, const bool loop_allocated,
const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated,
- BLI_bitmap *mask, int looptri_num_active,
+ const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
/**
* Frees data allocated by a call to bvhtree_from_mesh_*.
*/
+void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data);
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
@@ -144,36 +179,14 @@ enum {
BVHTREE_FROM_EDGES = 1,
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
- /* all faces */
- BVHTREE_FROM_FACES_EDITMESH_ALL = 4,
- /* visible unselected, only used for transform snapping */
- BVHTREE_FROM_FACES_EDITMESH_SNAP = 5,
- // BVHTREE_FROM_EDGES_EDITMESH_SNAP = 6,
- BVHTREE_FROM_VERTS_EDITMESH_SNAP = 7,
};
-typedef struct LinkNode *BVHCache;
+typedef struct LinkNode BVHCache;
-
-/**
- * Queries a bvhcache for the cache bvhtree of the request type
- */
BVHTree *bvhcache_find(BVHCache *cache, int type);
-
-/**
- * Inserts a BVHTree of the given type under the cache
- * After that the caller no longer needs to worry when to free the BVHTree
- * as that will be done when the cache is freed.
- *
- * A call to this assumes that there was no previous cached tree of the given type
- */
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type);
-
-/**
- * inits and frees a bvhcache
- */
-void bvhcache_init(BVHCache *cache);
-void bvhcache_free(BVHCache *cache);
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
+void bvhcache_init(BVHCache **cache_p);
+void bvhcache_free(BVHCache **cache_p);
#endif
-
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 28de270bbd1..50fcbd8e139 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -115,7 +115,7 @@ typedef struct ClothVertex {
float mass; /* mass / weight of the vertex */
float goal; /* goal, from SB */
float impulse[3]; /* used in collision.c */
- float *xrest; /* temporary valid for building springs */
+ float xrest[3]; /* rest position of the vertex */
unsigned int impulse_count; /* same as above */
float avg_spring_len; /* average length of connected springs */
float struct_stiff;
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 17ad51a7a16..2cdda34b9b5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -244,7 +244,7 @@ void CustomData_free_elem(struct CustomData *data, int index, int count);
*/
void CustomData_interp(
const struct CustomData *source, struct CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index);
void CustomData_bmesh_interp_n(
struct CustomData *data, const void **src_blocks, const float *weights,
@@ -358,7 +358,7 @@ void CustomData_file_write_prepare(
struct CustomDataLayer **r_write_layers, struct CustomDataLayer *write_layers_buff, size_t write_layers_size);
/* query info over types */
-void CustomData_file_write_info(int type, const char **structname, int *structnum);
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
/* get the name of a layer type */
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 664338214bf..2022d11d508 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -93,7 +93,11 @@ void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
void fcurve_free_driver(struct FCurve *fcu);
struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver);
-void driver_free_variable(struct ChannelDriver *driver, struct DriverVar *dvar);
+void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
+
+void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+
void driver_change_variable_type(struct DriverVar *dvar, int type);
void driver_variable_name_validate(struct DriverVar *dvar);
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 894ccae0dc8..eb98268c9f0 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -61,6 +61,8 @@ void BKE_image_free_buffers(struct Image *image);
/* call from library */
void BKE_image_free(struct Image *image);
+void BKE_image_init(struct Image *image);
+
typedef void (StampCallback)(void *data, const char *propname, char *propvalue, int len);
void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr, bool allocate_only);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 21585a160dd..2215fbfbd7d 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -119,7 +119,8 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain);
/* (MAX_ID_NAME - 2) + 3 */
void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
-void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only, bool set_fake);
+void BKE_library_make_local(
+ struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 2f85db4d5d2..25893d54dca 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -61,8 +61,10 @@ typedef enum {
MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2,
} eMaskhandleMode;
-struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
-struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(struct MaskSpline *spline, struct MaskSplinePoint *point_ref);
+struct MaskSplinePoint *BKE_mask_spline_point_array(
+ struct MaskSpline *spline);
+struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
+ struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
/* mask layers */
struct MaskLayer *BKE_mask_layer_new(struct Mask *mask, const char *name);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index a8f20a4ebc5..c7d5857b873 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -69,7 +69,7 @@ extern "C" {
/* *** mesh.c *** */
-struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
+struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index);
int poly_find_loop_from_vert(
const struct MPoly *poly,
@@ -293,8 +293,9 @@ void BKE_mesh_loops_to_mface_corners(
void BKE_mesh_loops_to_tessdata(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
-void BKE_mesh_tangent_loops_to_tessdata(struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
+void BKE_mesh_tangent_loops_to_tessdata(
+ struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
+ int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name);
int BKE_mesh_recalc_tessellation(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
struct MVert *mvert,
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 455912ab819..f6c08909d23 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -101,7 +101,8 @@ typedef enum {
eModifierTypeFlag_NoUserAdd = (1 << 8),
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
- eModifierTypeFlag_UsesPreview = (1 << 9)
+ eModifierTypeFlag_UsesPreview = (1 << 9),
+ eModifierTypeFlag_AcceptsLattice = (1 << 10),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 2ece0f7a028..76e49566d19 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -642,12 +642,12 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
* Examples:
*
* \code{.c}
- * FOREACH_NODETREE(bmain, nodetree) {
+ * FOREACH_NODETREE(bmain, nodetree, id) {
* if (id == nodetree)
* printf("This is a linkable node tree");
* } FOREACH_NODETREE_END
*
- * FOREACH_NODETREE(bmain, nodetree) {
+ * FOREACH_NODETREE(bmain, nodetree, id) {
* if (nodetree->idname == "ShaderNodeTree")
* printf("This is a shader node tree);
* if (GS(id) == ID_MA)
diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h
index c4cfcba4b35..9b9c125fbe6 100644
--- a/source/blender/blenkernel/BKE_sketch.h
+++ b/source/blender/blenkernel/BKE_sketch.h
@@ -82,7 +82,6 @@ typedef struct SK_Intersection {
typedef struct SK_Sketch {
ListBase strokes;
- ListBase depth_peels;
SK_Stroke *active_stroke;
SK_Stroke *gesture;
SK_Point next_point;
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index b351bc6fe3e..278b303a315 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -54,11 +54,11 @@ bool bUnit_IsValid(int system, int type);
/* loop over scales, coudl add names later */
//double bUnit_Iter(void **unit, char **name, int system, int type);
-void bUnit_GetSystem(void **usys_pt, int *len, int system, int type);
-int bUnit_GetBaseUnit(void *usys_pt);
-const char *bUnit_GetName(void *usys_pt, int index);
-const char *bUnit_GetNameDisplay(void *usys_pt, int index);
-double bUnit_GetScaler(void *usys_pt, int index);
+void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len);
+int bUnit_GetBaseUnit(const void *usys_pt);
+const char *bUnit_GetName(const void *usys_pt, int index);
+const char *bUnit_GetNameDisplay(const void *usys_pt, int index);
+double bUnit_GetScaler(const void *usys_pt, int index);
/* aligned with PropertyUnit */
enum {
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 7311f330962..afab0ccc5a5 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -75,6 +75,9 @@ set(SRC
intern/armature_update.c
intern/autoexec.c
intern/blender.c
+ intern/blender_copybuffer.c
+ intern/blender_undo.c
+ intern/blendfile.c
intern/bmfont.c
intern/boids.c
intern/bpath.c
@@ -194,6 +197,10 @@ set(SRC
BKE_armature.h
BKE_autoexec.h
BKE_blender.h
+ BKE_blender_copybuffer.h
+ BKE_blender_undo.h
+ BKE_blender_version.h
+ BKE_blendfile.h
BKE_bmfont.h
BKE_bmfont_types.h
BKE_boids.h
@@ -414,7 +421,7 @@ if(WITH_PYTHON)
endif()
- if (PYTHON_EXECUTABLE)
+ if(PYTHON_EXECUTABLE)
get_filename_component(_python_exe_name ${PYTHON_EXECUTABLE} NAME)
add_definitions(-DPYTHON_EXECUTABLE_NAME=${_python_exe_name})
unset(_python_exe_name)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index d120678c005..1bfc3d90730 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -49,6 +49,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_linklist.h"
+#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
@@ -595,50 +596,49 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
int mf_idx;
int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- unsigned int (*loopindex)[4];
+ unsigned int (*loopindex)[4] = NULL;
/* Should never occure, but better abort than segfault! */
if (!polyindex)
return;
if (generate) {
- for (int i = 0; i < ldata->totlayer; i++) {
- if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[i].name);
- }
- }
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
- }
-
- BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
-
- loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
-
- for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
- const int mf_len = mf->v4 ? 4 : 3;
- unsigned int *ml_idx = loopindex[mf_idx];
- int i, not_done;
+ for (int j = 0; j < ldata->totlayer; j++) {
+ if (ldata->layers[j].type == CD_TANGENT) {
+ CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
+ CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+
+ if (!loopindex) {
+ loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
+ for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
+ const int mf_len = mf->v4 ? 4 : 3;
+ unsigned int *ml_idx = loopindex[mf_idx];
+
+ /* Find out loop indices. */
+ /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
+ for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
+ const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
+ if (tf_v != -1) {
+ ml_idx[tf_v] = i;
+ not_done--;
+ }
+ }
+ }
+ }
- /* Find out loop indices. */
- /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
- for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
- const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
- if (tf_v != -1) {
- ml_idx[tf_v] = i;
- not_done--;
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
+ * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
+ * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
+ */
+ BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name);
}
}
+ if (loopindex)
+ MEM_freeN(loopindex);
+ BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
}
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
- * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
- * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
- */
- BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface);
-
- MEM_freeN(loopindex);
-
if (G.debug & G_DEBUG)
printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm);
}
@@ -647,13 +647,15 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
void DM_update_materials(DerivedMesh *dm, Object *ob)
{
int i, totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */
- dm->totmat = totmat;
- /* invalidate old materials */
- if (dm->mat)
- MEM_freeN(dm->mat);
+ if (dm->totmat != totmat) {
+ dm->totmat = totmat;
+ /* invalidate old materials */
+ if (dm->mat)
+ MEM_freeN(dm->mat);
- dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
+ dm->mat = MEM_mallocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
+ }
/* we leave last material as empty - rationale here is being able to index
* the materials by using the mf->mat_nr directly and leaving the last
@@ -661,6 +663,7 @@ void DM_update_materials(DerivedMesh *dm, Object *ob)
for (i = 0; i < totmat - 1; i++) {
dm->mat[i] = give_current_material(ob, i + 1);
}
+ dm->mat[i] = NULL;
}
MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
@@ -3207,96 +3210,28 @@ finally:
pRes[3] = fSign;
}
-void DM_calc_loop_tangents(DerivedMesh *dm)
+void DM_calc_tangents_names_from_gpu(
+ const GPUVertexAttribs *gattribs,
+ char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
{
- /* mesh vars */
- const MLoopTri *looptri;
- MVert *mvert;
- MLoopUV *mloopuv;
- MPoly *mpoly;
- MLoop *mloop;
- float (*orco)[3] = NULL, (*tangent)[4];
- int /* totvert, */ totface;
- float (*fnors)[3];
- float (*tlnors)[3];
-
- if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
- return;
-
- fnors = dm->getPolyDataArray(dm, CD_NORMAL);
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
-
- /* check we have all the needed layers */
- /* totvert = dm->getNumVerts(dm); */ /* UNUSED */
- looptri = dm->getLoopTriArray(dm);
- totface = dm->getNumLoopTri(dm);
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
-
- if (!mloopuv) {
- orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!orco)
- return;
- }
-
- /* create tangent layer */
- DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
- tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (totface != dm->getNumPolys(dm)) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (mpoly[looptri[j].poly].totloop == 4) {
- j++; /* skips the nest looptri */
- }
+ int count = 0;
+ for (int b = 0; b < gattribs->totlayer; b++) {
+ if (gattribs->layer[b].type == CD_TANGENT) {
+ strcpy(tangent_names[count++], gattribs->layer[b].name);
}
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
}
-#endif
+ *r_tangent_names_count = count;
+}
+static void DM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
{
- SGLSLMeshToTangent mesh2tangent = {NULL};
SMikkTSpaceContext sContext = {NULL};
SMikkTSpaceInterface sInterface = {NULL};
- mesh2tangent.precomputedFaceNormals = fnors;
- mesh2tangent.precomputedLoopNormals = tlnors;
- mesh2tangent.looptri = looptri;
- mesh2tangent.mloopuv = mloopuv;
- mesh2tangent.mpoly = mpoly;
- mesh2tangent.mloop = mloop;
- mesh2tangent.mvert = mvert;
- mesh2tangent.orco = orco;
- mesh2tangent.tangent = tangent;
- mesh2tangent.numTessFaces = totface;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent.face_as_quad_map = face_as_quad_map;
- mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
-#endif
-
- sContext.m_pUserData = &mesh2tangent;
+ sContext.m_pUserData = mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = dm_ts_GetNumFaces;
sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
@@ -3307,13 +3242,211 @@ void DM_calc_loop_tangents(DerivedMesh *dm)
/* 0 if failed */
genTangSpaceDefault(&sContext);
+ }
+}
+
+void DM_add_named_tangent_layer_for_uv(
+ CustomData *uv_data, CustomData *tan_data, int numLoopData,
+ const char *layer_name)
+{
+ if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+ CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
+ {
+ CustomData_add_layer_named(
+ tan_data, CD_TANGENT, CD_CALLOC, NULL,
+ numLoopData, layer_name);
+ }
+}
+
+/**
+ * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
+void DM_calc_loop_tangents_step_0(
+ const CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
+ /* Active uv in viewport */
+ *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+ ract_uv_name[0] = 0;
+ if (*ract_uv_n != -1) {
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+ }
+
+ /* Active tangent in render */
+ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+ rren_uv_name[0] = 0;
+ if (*rren_uv_n != -1) {
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+ }
+
+ /* If active tangent not in tangent_names we take it into account */
+ *rcalc_act = false;
+ *rcalc_ren = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] == 0) {
+ calc_active_tangent = true;
+ }
+ }
+ if (calc_active_tangent) {
+ *rcalc_act = true;
+ *rcalc_ren = true;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (STREQ(ract_uv_name, tangent_names[i]))
+ *rcalc_act = false;
+ if (STREQ(rren_uv_name, tangent_names[i]))
+ *rcalc_ren = false;
+ }
+ }
+ *rtangent_mask = 0;
+
+ const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+ for (int n = 0; n < uv_layer_num; n++) {
+ const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+ bool add = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+ add = true;
+ break;
+ }
+ }
+ if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+ (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
+ {
+ add = true;
+ }
+ if (add)
+ *rtangent_mask |= 1 << n;
+ }
+}
+
+void DM_calc_loop_tangents(
+ DerivedMesh *dm, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count)
+{
+ if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
+ return;
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ char tangent_mask = 0;
+ DM_calc_loop_tangents_step_0(
+ &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+ if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
+ /* Check we have all the needed layers */
+ MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoopTri *looptri = dm->getLoopTriArray(dm);
+ int totface = dm->getNumLoopTri(dm);
+ /* Allocate needed tangent layers */
+ for (int i = 0; i < tangent_names_count; i++)
+ if (tangent_names[i][0])
+ DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
+ if (calc_act && act_uv_name[0])
+ DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (totface != dm->getNumPolys(dm)) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int k, j;
+ for (k = 0, j = 0; j < totface; k++, j++) {
+ face_as_quad_map[k] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = k;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+
+ /* Calculation */
+ {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ dm->tangent_mask = 0;
+ /* Calculate tangent layers */
+ SGLSLMeshToTangent data_array[MAX_MTFACE];
+ const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
+ for (int n = 0; n < tangent_layer_num; n++) {
+ int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = totface;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->mvert = dm->getVertArray(dm);
+ mesh2tangent->mpoly = dm->getPolyArray(dm);
+ mesh2tangent->mloop = dm->getLoopArray(dm);
+ mesh2tangent->looptri = dm->getLoopTriArray(dm);
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
+ mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+ mesh2tangent->orco = NULL;
+ mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+ if (!mesh2tangent->mloopuv) {
+ mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
+ if (!mesh2tangent->orco)
+ continue;
+ }
+ mesh2tangent->tangent = dm->loopData.layers[index].data;
+
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+ int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ dm->tangent_mask |= 1 << (uv_ind - uv_start);
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+ BLI_assert(dm->tangent_mask == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
#ifdef USE_LOOPTRI_DETECT_QUADS
if (face_as_quad_map) {
MEM_freeN(face_as_quad_map);
}
#undef USE_LOOPTRI_DETECT_QUADS
+
#endif
+
+ int uv_index, tan_index;
+
+ /* Update active layer index */
+ uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
+ tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+
+ /* Update render layer index */
+ uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
+ tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
}
}
@@ -3487,15 +3620,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
if (dm->auto_bump_scale <= 0.0f)
DM_calc_auto_bump_scale(dm);
- /* add a tangent layer if necessary */
- for (b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_TANGENT) {
- if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
- dm->calcLoopTangents(dm);
- }
- break;
- }
- }
+ char tangent_names[MAX_MTFACE][MAX_NAME];
+ int tangent_names_count;
+ /* Add a tangent layer/layers. */
+ DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
+
+ if (tangent_names_count)
+ dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
if (gattribs->layer[b].type == CD_MTFACE) {
@@ -3541,20 +3672,24 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
else if (gattribs->layer[b].type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
- layer = CustomData_get_layer_index(&dm->loopData, CD_TANGENT);
- attribs->tottang = 1;
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+
+ a = attribs->tottang++;
if (layer != -1) {
- attribs->tang.array = dm->loopData.layers[layer].data;
- attribs->tang.em_offset = dm->loopData.layers[layer].offset;
+ attribs->tang[a].array = dm->loopData.layers[layer].data;
+ attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
}
else {
- attribs->tang.array = NULL;
- attribs->tang.em_offset = -1;
+ attribs->tang[a].array = NULL;
+ attribs->tang[a].em_offset = -1;
}
- attribs->tang.gl_index = gattribs->layer[b].glindex;
+ attribs->tang[a].gl_index = gattribs->layer[b].glindex;
}
else if (gattribs->layer[b].type == CD_ORCO) {
/* original coordinates */
@@ -3636,10 +3771,12 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
}
/* tangent for normal mapping */
- if (attribs->tottang) {
- /*const*/ float (*array)[4] = attribs->tang.array;
- const float *tang = (array) ? array[loop] : zero;
- glVertexAttrib4fv(attribs->tang.gl_index, tang);
+ for (b = 0; b < attribs->tottang; b++) {
+ if (attribs->tang[b].array) {
+ /*const*/ float (*array)[4] = attribs->tang[b].array;
+ const float *tang = (array) ? array[a * 4 + vert] : zero;
+ glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
+ }
}
}
@@ -3863,7 +4000,7 @@ void DM_init_origspace(DerivedMesh *dm)
float p_nor[3], co[3];
float mat[3][3];
- float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
float translate[2], scale[2];
BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 3e1cf6a74a4..3a31e4c36cf 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -493,6 +493,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
+ chan->scaleIn = chan->scaleOut = 1.0f;
+
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
@@ -824,26 +826,35 @@ void BKE_pose_channels_free(bPose *pose)
BKE_pose_channels_free_ex(pose, true);
}
+void BKE_pose_free_data_ex(bPose *pose, bool do_id_user)
+{
+ /* free pose-channels */
+ BKE_pose_channels_free_ex(pose, do_id_user);
+
+ /* free pose-groups */
+ if (pose->agroups.first)
+ BLI_freelistN(&pose->agroups);
+
+ /* free IK solver state */
+ BIK_clear_data(pose);
+
+ /* free IK solver param */
+ if (pose->ikparam)
+ MEM_freeN(pose->ikparam);
+}
+
+void BKE_pose_free_data(bPose *pose)
+{
+ BKE_pose_free_data_ex(pose, true);
+}
+
/**
* Removes and deallocates all data from a pose, and also frees the pose.
*/
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
if (pose) {
- /* free pose-channels */
- BKE_pose_channels_free_ex(pose, do_id_user);
-
- /* free pose-groups */
- if (pose->agroups.first)
- BLI_freelistN(&pose->agroups);
-
- /* free IK solver state */
- BIK_clear_data(pose);
-
- /* free IK solver param */
- if (pose->ikparam)
- MEM_freeN(pose->ikparam);
-
+ BKE_pose_free_data_ex(pose, do_id_user);
/* free pose */
MEM_freeN(pose);
}
@@ -1271,6 +1282,18 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
}
}
+ if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
+ /* bbone shape properties */
+ pPtr = strstr(bPtr, "bbone_");
+ if (pPtr) {
+ flags |= ACT_TRANS_BBONE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
@@ -1414,6 +1437,18 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
workob->constraints.last = ob->constraints.last;
workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */
+ if (pose) {
+ /* This function is most likely to be used with a temporary pose with a single bone in there.
+ * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory
+ * allocation and also will make lookup slower.
+ */
+ if (pose->chanbase.first != pose->chanbase.last) {
+ BKE_pose_channels_hash_make(pose);
+ }
+ if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(pose);
+ }
+ }
BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index de21d9105e2..b1dcc40279f 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -32,7 +32,7 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
-#include "BKE_blender.h" /* BLENDER_VERSION */
+#include "BKE_blender_version.h"
#include "BKE_appdir.h" /* own include */
#include "GHOST_Path-api.h"
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 54fe98940aa..5c95cde4d8d 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -41,6 +41,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -48,6 +49,7 @@
#include "DNA_constraint_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_listBase.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -427,7 +429,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-static void equalize_bezier(float *data, int desired)
+void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -497,13 +499,21 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
hlength2 = bone->ease2 * length * 0.390464f;
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
+ /* get "next" and "prev" bones - these are used for handle calculations */
+ if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
+ /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
+ prev = pchan->bbone_prev;
+ next = pchan->bbone_next;
+ }
+ else {
+ /* evaluate next and prev bones */
+ if (bone->flag & BONE_CONNECTED)
+ prev = pchan->parent;
+ else
+ prev = NULL;
- next = pchan->child;
+ next = pchan->child;
+ }
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
@@ -523,10 +533,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform previous point inside this bone space */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ if (rest) {
+ /* in restpose, arm_head == pose_head */
+ h1[0] = h1[1] = h1[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else {
+ /* Use bone head as absolute position */
+ if (rest)
+ copy_v3_v3(h1, prev->bone->arm_head);
+ else
+ copy_v3_v3(h1, prev->pose_head);
+ }
mul_m4_v3(imat, h1);
if (prev->bone->segments > 1) {
@@ -562,10 +589,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform next point inside this bone space */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ if (rest) {
+ /* in restpose, arm_tail == pose_tail */
+ h2[0] = h2[1] = h2[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Use bone tail as absolute position */
+ if (rest)
+ copy_v3_v3(h2, next->bone->arm_tail);
+ else
+ copy_v3_v3(h2, next->pose_tail);
+ }
mul_m4_v3(imat, h2);
/* if next bone is B-bone too, use average handle direction */
@@ -599,6 +643,50 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = 0.0;
}
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ /* add extra rolls */
+ roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone)
+ roll1 += prev->bone->roll2;
+
+ if (!rest)
+ roll1 += prev->roll2;
+ }
+ }
+
+ /* extra curve x / y */
+ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
+ * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
+ * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
+ */
+ const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
+ const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+
+ h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
+ h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+
+ h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
+ h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ }
+
/* make curve */
if (bone->segments > MAX_BBONE_SUBDIV)
bone->segments = MAX_BBONE_SUBDIV;
@@ -608,20 +696,45 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
-
+
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
-
+
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
+
+ /* BBone scale... */
+ {
+ const int num_segments = bone->segments;
+
+ const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+
+ const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ /*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+
}
}
@@ -633,7 +746,7 @@ typedef struct bPoseChanDeform {
DualQuat *b_bone_dual_quats;
} bPoseChanDeform;
-static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, int use_quaternion)
+static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, const bool use_quaternion)
{
Bone *bone = pchan->bone;
Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV];
@@ -667,7 +780,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
float tmat[4][4];
invert_m4_m4(tmat, b_bone_rest[a].mat);
-
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
@@ -681,10 +793,10 @@ static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], D
float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
-
+
/* need to transform co back to bonespace, only need y */
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
-
+
/* now calculate which of the b_bones are deforming this */
segment = bone->length / ((float)bone->segments);
a = (int)(y / segment);
@@ -854,6 +966,32 @@ static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
(*contrib) += weight;
}
+typedef struct ArmatureBBoneDefmatsData {
+ bPoseChanDeform *pdef_info_array;
+ DualQuat *dualquats;
+ bool use_quaternion;
+} ArmatureBBoneDefmatsData;
+
+static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
+{
+ ArmatureBBoneDefmatsData *data = userdata;
+ bPoseChannel *pchan = (bPoseChannel *)iter;
+
+ if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
+ bPoseChanDeform *pdef_info = &data->pdef_info_array[index];
+ const bool use_quaternion = data->use_quaternion;
+
+ if (pchan->bone->segments > 1) {
+ pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
+ }
+
+ if (use_quaternion) {
+ pdef_info->dual_quat = &data->dualquats[index];
+ mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
+ }
+ }
+}
+
void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts, int deformflag,
float (*prevCos)[3], const char *defgrp_name)
@@ -867,16 +1005,19 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
bDeformGroup *dg;
DualQuat *dualquats = NULL;
float obinv[4][4], premat[4][4], postmat[4][4];
- const short use_envelope = deformflag & ARM_DEF_ENVELOPE;
- const short use_quaternion = deformflag & ARM_DEF_QUATERNION;
- const short invert_vgroup = deformflag & ARM_DEF_INVERT_VGROUP;
+ const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
+ const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
+ const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
int defbase_tot = 0; /* safety for vertexgroup index overflow */
int i, target_totvert = 0; /* safety for vertexgroup overflow */
bool use_dverts = false;
int armature_def_nr;
int totchan;
- if (arm->edbo) return;
+ /* in editmode, or not an armature */
+ if (arm->edbo || (armOb->pose == NULL)) {
+ return;
+ }
invert_m4_m4(obinv, target->obmat);
copy_m4_m4(premat, target->obmat);
@@ -894,19 +1035,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
pdef_info_array = MEM_callocN(sizeof(bPoseChanDeform) * totchan, "bPoseChanDeform");
- totchan = 0;
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
- if (pchan->bone->segments > 1)
- pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
-
- if (use_quaternion) {
- pdef_info->dual_quat = &dualquats[totchan++];
- mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
- }
- }
- }
+ ArmatureBBoneDefmatsData data = {
+ .pdef_info_array = pdef_info_array, .dualquats = dualquats, .use_quaternion = use_quaternion
+ };
+ BLI_task_parallel_listbase(&armOb->pose->chanbase, &data, armature_bbone_defmats_cb, totchan > 512);
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = defgroup_name_index(target, defgrp_name);
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index ceda9f056bb..826bb12a912 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -619,7 +619,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
else {
/* TODO(sergey): Use time source node for time. */
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ if ((pchan->flag & POSE_DONE) == 0) {
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
}
}
}
@@ -631,12 +633,18 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
- if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ bArmature *arm = (bArmature *)ob->data;
+ if (arm->flag & ARM_RESTPOS) {
+ return;
+ }
+ else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
/* IK are being solved separately/ */
}
else {
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ if ((pchan->flag & POSE_DONE) == 0) {
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index baf93ffd824..15492fbd20d 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -27,89 +27,55 @@
/** \file blender/blenkernel/intern/blender.c
* \ingroup bke
+ *
+ * Application level startup/shutdown functionality.
*/
-#ifndef _GNU_SOURCE
-/* Needed for O_NOFOLLOW on some platforms. */
-# define _GNU_SOURCE 1
-#endif
-
-#ifndef _WIN32
-# include <unistd.h> // for read close
-#else
-# include <io.h> // for open close read
-#endif
-
#include <stdlib.h>
#include <stdio.h>
-#include <stddef.h>
#include <string.h>
-#include <fcntl.h> /* for open */
-#include <errno.h>
#include "MEM_guardedalloc.h"
-#include "DNA_userdef_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_windowmanager_types.h"
-
-#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
-#include "BKE_appdir.h"
-#include "BKE_blender.h"
-#include "BKE_bpath.h"
+#include "BKE_blender.h" /* own include */
+#include "BKE_blender_version.h" /* own include */
+#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
-#include "BKE_ipo.h"
#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
-#include "BKE_sound.h"
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "BLF_api.h"
-#include "BLO_undofile.h"
-#include "BLO_readfile.h"
-#include "BLO_writefile.h"
-
-#include "RNA_access.h"
-
-#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie
-
-#include "IMB_colormanagement.h"
-
-#ifdef WITH_PYTHON
-# include "BPY_extern.h"
-#endif
Global G;
UserDef U;
-/* ListBase = {NULL, NULL}; */
char versionstr[48] = "";
/* ********** free ********** */
/* only to be called on exit blender */
-void free_blender(void)
+void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G.main->sound->sample NULL */
BKE_main_free(G.main);
@@ -132,7 +98,7 @@ void free_blender(void)
free_nodesystem();
}
-void initglobals(void)
+void BKE_blender_globals_init(void)
{
memset(&G, 0, sizeof(Global));
@@ -154,300 +120,14 @@ void initglobals(void)
#endif
}
-/***/
-
-static void clear_global(void)
+void BKE_blender_globals_clear(void)
{
-// extern short winqueue_break; /* screen.c */
-
BKE_main_free(G.main); /* free all lib data */
-
-// free_vertexpaint();
G.main = NULL;
}
-static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
-{
- strcpy(path_dst, path_src);
- BLI_path_native_slash(path_dst);
- return !STREQ(path_dst, path_src);
-}
-
-/* make sure path names are correct for OS */
-static void clean_paths(Main *main)
-{
- Scene *scene;
-
- BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
-
- for (scene = main->scene.first; scene; scene = scene->id.next) {
- BLI_path_native_slash(scene->r.pic);
- }
-}
-
-static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
-{
- wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->scene == scene) {
- return true;
- }
- }
- return false;
-}
-
-/**
- * Context matching, handle no-ui case
- *
- * \note this is called on Undo so any slow conversion functions here
- * should be avoided or check (mode != LOAD_UNDO).
- *
- * \param bfd: Blend file data, freed by this function on exit.
- * \param filepath: File path or identifier.
- */
-static void setup_app_data(
- bContext *C, BlendFileData *bfd,
- const char *filepath, ReportList *reports)
-{
- Scene *curscene = NULL;
- const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
- enum {
- LOAD_UI = 1,
- LOAD_UI_OFF,
- LOAD_UNDO,
- } mode;
-
- if (BLI_listbase_is_empty(&bfd->main->screen)) {
- mode = LOAD_UNDO;
- }
- else if (G.fileflags & G_FILE_NO_UI) {
- mode = LOAD_UI_OFF;
- }
- else {
- mode = LOAD_UI;
- }
-
- if (mode != LOAD_UNDO) {
- /* may happen with library files */
- if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
- BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
- mode = LOAD_UI_OFF;
- }
- }
-
- /* Free all render results, without this stale data gets displayed after loading files */
- if (mode != LOAD_UNDO) {
- RE_FreeAllRenderResults();
- }
-
- /* Only make filepaths compatible when loading for real (not undo) */
- if (mode != LOAD_UNDO) {
- clean_paths(bfd->main);
- }
-
- /* XXX here the complex windowmanager matching */
-
- /* no load screens? */
- if (mode != LOAD_UI) {
- /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
- * as long as the scene associated with the undo operation is visible in one of the open windows.
- *
- * - 'curscreen->scene' - scene the user is currently looking at.
- * - 'bfd->curscene' - scene undo-step was created in.
- *
- * This means users can have 2+ windows open and undo in both without screens switching.
- * But if they close one of the screens,
- * undo will ensure that the scene being operated on will be activated
- * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
- * see: T43424
- */
- bScreen *curscreen = NULL;
- bool track_undo_scene;
-
- /* comes from readfile.c */
- SWAP(ListBase, G.main->wm, bfd->main->wm);
- SWAP(ListBase, G.main->screen, bfd->main->screen);
-
- /* we re-use current screen */
- curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
- curscene = bfd->curscene;
-
- track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
-
- if (curscene == NULL) {
- curscene = bfd->main->scene.first;
- }
- /* empty file, we add a scene to make Blender work */
- if (curscene == NULL) {
- curscene = BKE_scene_add(bfd->main, "Empty");
- }
-
- if (track_undo_scene) {
- /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
- * replace it with 'curscene' if its needed */
- }
- else {
- /* and we enforce curscene to be in current screen */
- if (curscreen) {
- /* can run in bgmode */
- curscreen->scene = curscene;
- }
- }
-
- /* clear_global will free G.main, here we can still restore pointers */
- blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
- if (curscreen) {
- curscene = curscreen->scene;
- }
-
- if (track_undo_scene) {
- wmWindowManager *wm = bfd->main->wm.first;
- if (wm_scene_is_visible(wm, bfd->curscene) == false) {
- curscene = bfd->curscene;
- curscreen->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen);
- }
- }
- }
-
- /* free G.main Main database */
-// CTX_wm_manager_set(C, NULL);
- clear_global();
-
- /* clear old property update cache, in case some old references are left dangling */
- RNA_property_update_cache_free();
-
- G.main = bfd->main;
-
- CTX_data_main_set(C, G.main);
-
- if (bfd->user) {
-
- /* only here free userdef themes... */
- BKE_userdef_free();
-
- U = *bfd->user;
-
- /* Security issue: any blend file could include a USER block.
- *
- * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
- * to load the preferences defined in the users home dir.
- *
- * This means we will never accidentally (or maliciously)
- * enable scripts auto-execution by loading a '.blend' file.
- */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
-
- MEM_freeN(bfd->user);
- }
-
- /* case G_FILE_NO_UI or no screens in file */
- if (mode != LOAD_UI) {
- /* leave entire context further unaltered? */
- CTX_data_scene_set(C, curscene);
- }
- else {
- G.fileflags = bfd->fileflags;
- CTX_wm_manager_set(C, G.main->wm.first);
- CTX_wm_screen_set(C, bfd->curscreen);
- CTX_data_scene_set(C, bfd->curscene);
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
- CTX_wm_menu_set(C, NULL);
- curscene = bfd->curscene;
- }
-
- /* this can happen when active scene was lib-linked, and doesn't exist anymore */
- if (CTX_data_scene(C) == NULL) {
- /* in case we don't even have a local scene, add one */
- if (!G.main->scene.first)
- BKE_scene_add(G.main, "Empty");
-
- CTX_data_scene_set(C, G.main->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
- curscene = CTX_data_scene(C);
- }
-
- BLI_assert(curscene == CTX_data_scene(C));
-
-
- /* special cases, override loaded flags: */
- if (G.f != bfd->globalf) {
- const int flags_keep = (G_SWAP_EXCHANGE | G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
- bfd->globalf = (bfd->globalf & ~flags_keep) | (G.f & flags_keep);
- }
-
-
- G.f = bfd->globalf;
-
-#ifdef WITH_PYTHON
- /* let python know about new main */
- BPY_context_update(C);
-#endif
-
- /* FIXME: this version patching should really be part of the file-reading code,
- * but we still get too many unrelated data-corruption crashes otherwise... */
- if (G.main->versionfile < 250)
- do_versions_ipos_to_animato(G.main);
-
- G.main->recovered = 0;
-
- /* startup.blend or recovered startup */
- if (bfd->filename[0] == 0) {
- G.main->name[0] = 0;
- }
- else if (recover && G.relbase_valid) {
- /* in case of autosave or quit.blend, use original filename instead
- * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
- filepath = bfd->filename;
- G.main->recovered = 1;
-
- /* these are the same at times, should never copy to the same location */
- if (G.main->name != filepath)
- BLI_strncpy(G.main->name, filepath, FILE_MAX);
- }
-
- /* baseflags, groups, make depsgraph, etc */
- /* first handle case if other windows have different scenes visible */
- if (mode == LOAD_UI) {
- wmWindowManager *wm = G.main->wm.first;
-
- if (wm) {
- wmWindow *win;
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != curscene)
- BKE_scene_set_background(G.main, win->screen->scene);
- }
- }
- }
- BKE_scene_set_background(G.main, curscene);
-
- if (mode != LOAD_UNDO) {
- RE_FreeAllPersistentData();
- IMB_colormanagement_check_file_config(G.main);
- }
-
- MEM_freeN(bfd);
-
-}
-
-static int handle_subversion_warning(Main *main, ReportList *reports)
-{
- if (main->minversionfile > BLENDER_VERSION ||
- (main->minversionfile == BLENDER_VERSION &&
- main->minsubversionfile > BLENDER_SUBVERSION))
- {
- BKE_reportf(reports, RPT_ERROR, "File written by newer Blender binary (%d.%d), expect loss of data!",
- main->minversionfile, main->minsubversionfile);
- }
-
- return 1;
-}
+/***/
static void keymap_item_free(wmKeyMapItem *kmi)
{
@@ -459,7 +139,11 @@ static void keymap_item_free(wmKeyMapItem *kmi)
MEM_freeN(kmi->ptr);
}
-void BKE_userdef_free(void)
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
+void BKE_blender_userdef_free(void)
{
wmKeyMap *km;
wmKeyMapItem *kmi;
@@ -509,8 +193,10 @@ void BKE_userdef_free(void)
BLI_freelistN(&U.user_keymaps);
}
-/* handle changes in settings that need recalc */
-void BKE_userdef_state(void)
+/**
+ * Handle changes in settings that need refreshing.
+ */
+void BKE_blender_userdef_refresh(void)
{
/* prevent accidents */
if (U.pixelsize == 0) U.pixelsize = 1;
@@ -520,116 +206,6 @@ void BKE_userdef_state(void)
}
-int BKE_read_file(bContext *C, const char *filepath, ReportList *reports)
-{
- BlendFileData *bfd;
- int retval = BKE_READ_FILE_OK;
-
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
- printf("read blend: %s\n", filepath);
-
- bfd = BLO_read_from_file(filepath, reports);
- if (bfd) {
- if (bfd->user) retval = BKE_READ_FILE_OK_USERPREFS;
-
- if (0 == handle_subversion_warning(bfd->main, reports)) {
- BKE_main_free(bfd->main);
- MEM_freeN(bfd);
- bfd = NULL;
- retval = BKE_READ_FILE_FAIL;
- }
- else {
- setup_app_data(C, bfd, filepath, reports);
- }
- }
- else
- BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
-
- return (bfd ? retval : BKE_READ_FILE_FAIL);
-}
-
-bool BKE_read_file_from_memory(
- bContext *C, const void *filebuf, int filelength,
- ReportList *reports, bool update_defaults)
-{
- BlendFileData *bfd;
-
- bfd = BLO_read_from_memory(filebuf, filelength, reports);
- if (bfd) {
- if (update_defaults)
- BLO_update_defaults_startup_blend(bfd->main);
- setup_app_data(C, bfd, "<memory2>", reports);
- }
- else {
- BKE_reports_prepend(reports, "Loading failed: ");
- }
-
- return (bfd != NULL);
-}
-
-/* memfile is the undo buffer */
-bool BKE_read_file_from_memfile(
- bContext *C, MemFile *memfile,
- ReportList *reports)
-{
- BlendFileData *bfd;
-
- bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports);
- if (bfd) {
- /* remove the unused screens and wm */
- while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
- while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
-
- setup_app_data(C, bfd, "<memory1>", reports);
- }
- else {
- BKE_reports_prepend(reports, "Loading failed: ");
- }
-
- return (bfd != NULL);
-}
-
-/* only read the userdef from a .blend */
-int BKE_read_file_userdef(const char *filepath, ReportList *reports)
-{
- BlendFileData *bfd;
- int retval = BKE_READ_FILE_FAIL;
-
- bfd = BLO_read_from_file(filepath, reports);
- if (bfd) {
- if (bfd->user) {
- retval = BKE_READ_FILE_OK_USERPREFS;
-
- /* only here free userdef themes... */
- BKE_userdef_free();
-
- U = *bfd->user;
- MEM_freeN(bfd->user);
- }
- BKE_main_free(bfd->main);
- MEM_freeN(bfd);
- }
-
- return retval;
-}
-
-/* only write the userdef in a .blend */
-int BKE_write_file_userdef(const char *filepath, ReportList *reports)
-{
- Main *mainb = MEM_callocN(sizeof(Main), "empty main");
- int retval = 0;
-
- if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) {
- retval = 1;
- }
-
- MEM_freeN(mainb);
-
- return retval;
-}
-
/* ***************** testing for break ************* */
static void (*blender_test_break_cb)(void) = NULL;
@@ -640,7 +216,7 @@ void BKE_blender_callback_test_break_set(void (*func)(void))
}
-int blender_test_break(void)
+int BKE_blender_test_break(void)
{
if (!G.background) {
if (blender_test_break_cb)
@@ -650,514 +226,3 @@ int blender_test_break(void)
return (G.is_break == true);
}
-
-/* -------------------------------------------------------------------- */
-
-/** \name Global Undo
- * \{ */
-
-#define UNDO_DISK 0
-
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- char str[FILE_MAX];
- char name[BKE_UNDO_STR_MAX];
- MemFile memfile;
- uintptr_t undosize;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
-
-
-static int read_undosave(bContext *C, UndoElem *uel)
-{
- char mainstr[sizeof(G.main->name)];
- 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));
-
- BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
-
- fileflags = G.fileflags;
- G.fileflags |= G_FILE_NO_UI;
-
- if (UNDO_DISK)
- success = (BKE_read_file(C, uel->str, NULL) != BKE_READ_FILE_FAIL);
- else
- success = BKE_read_file_from_memfile(C, &uel->memfile, NULL);
-
- /* restore */
- BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
- G.fileflags = fileflags;
-
- if (success) {
- /* important not to update time here, else non keyed tranforms are lost */
- DAG_on_visible_update(G.main, false);
- }
-
- return success;
-}
-
-/* name can be a dynamic string */
-void BKE_undo_write(bContext *C, const char *name)
-{
- uintptr_t maxmem, totmem, memused;
- int nr /*, success */ /* UNUSED */;
- UndoElem *uel;
-
- if ((U.uiflag & USER_GLOBALUNDO) == 0) {
- return;
- }
-
- if (U.undosteps == 0) {
- return;
- }
-
- /* remove all undos after (also when curundo == NULL) */
- while (undobase.last != curundo) {
- uel = undobase.last;
- BLI_remlink(&undobase, uel);
- BLO_memfile_free(&uel->memfile);
- MEM_freeN(uel);
- }
-
- /* make new */
- curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file");
- BLI_strncpy(uel->name, name, sizeof(uel->name));
- BLI_addtail(&undobase, uel);
-
- /* and limit amount to the maximum */
- nr = 0;
- uel = undobase.last;
- while (uel) {
- nr++;
- if (nr == U.undosteps) break;
- uel = uel->prev;
- }
- if (uel) {
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
- BLI_remlink(&undobase, first);
- /* the merge is because of compression */
- BLO_memfile_merge(&first->memfile, &first->next->memfile);
- MEM_freeN(first);
- }
- }
-
-
- /* disk save version */
- if (UNDO_DISK) {
- static int counter = 0;
- char filepath[FILE_MAX];
- char numstr[32];
- int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */
-
- /* calculate current filepath */
- counter++;
- counter = counter % U.undosteps;
-
- BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_make_file_string("/", filepath, BKE_tempdir_session(), numstr);
-
- /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
-
- BLI_strncpy(curundo->str, filepath, sizeof(curundo->str));
- }
- else {
- MemFile *prevfile = NULL;
-
- if (curundo->prev) prevfile = &(curundo->prev->memfile);
-
- memused = MEM_get_memory_in_use();
- /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags);
- curundo->undosize = MEM_get_memory_in_use() - memused;
- }
-
- if (U.undomemory != 0) {
- /* limit to maximum memory (afterwards, we can't know in advance) */
- totmem = 0;
- maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024;
-
- /* keep at least two (original + other) */
- uel = undobase.last;
- while (uel && uel->prev) {
- totmem += uel->undosize;
- if (totmem > maxmem) break;
- uel = uel->prev;
- }
-
- if (uel) {
- if (uel->prev && uel->prev->prev)
- uel = uel->prev;
-
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
- BLI_remlink(&undobase, first);
- /* the merge is because of compression */
- BLO_memfile_merge(&first->memfile, &first->next->memfile);
- MEM_freeN(first);
- }
- }
- }
-}
-
-/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
-void BKE_undo_step(bContext *C, int step)
-{
-
- if (step == 0) {
- read_undosave(C, curundo);
- }
- else if (step == 1) {
- /* curundo should never be NULL, after restart or load file it should call undo_save */
- if (curundo == NULL || curundo->prev == NULL) {
- // XXX error("No undo available");
- }
- else {
- if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
- curundo = curundo->prev;
- read_undosave(C, curundo);
- }
- }
- else {
- /* curundo has to remain current situation! */
-
- if (curundo == NULL || curundo->next == NULL) {
- // XXX error("No redo available");
- }
- else {
- read_undosave(C, curundo->next);
- curundo = curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name);
- }
- }
-}
-
-void BKE_undo_reset(void)
-{
- UndoElem *uel;
-
- uel = undobase.first;
- while (uel) {
- BLO_memfile_free(&uel->memfile);
- uel = uel->next;
- }
-
- BLI_freelistN(&undobase);
- curundo = NULL;
-}
-
-/* based on index nr it does a restore */
-void BKE_undo_number(bContext *C, int nr)
-{
- curundo = BLI_findlink(&undobase, nr);
- BKE_undo_step(C, 0);
-}
-
-/* go back to the last occurance of name in stack */
-void BKE_undo_name(bContext *C, const char *name)
-{
- UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
-
- if (uel && uel->prev) {
- curundo = uel->prev;
- BKE_undo_step(C, 0);
- }
-}
-
-/* name optional */
-bool BKE_undo_is_valid(const char *name)
-{
- if (name) {
- UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
- return uel && uel->prev;
- }
-
- return undobase.last != undobase.first;
-}
-
-/* get name of undo item, return null if no item with this index */
-/* if active pointer, set it to 1 if true */
-const char *BKE_undo_get_name(int nr, bool *r_active)
-{
- UndoElem *uel = BLI_findlink(&undobase, nr);
-
- if (r_active) *r_active = false;
-
- if (uel) {
- if (r_active && (uel == curundo)) {
- *r_active = true;
- }
- return uel->name;
- }
- return NULL;
-}
-
-/**
- * Saves .blend using undo buffer.
- *
- * \return success.
- */
-bool BKE_undo_save_file(const char *filename)
-{
- UndoElem *uel;
- MemFileChunk *chunk;
- int file, oflags;
-
- if ((U.uiflag & USER_GLOBALUNDO) == 0) {
- return false;
- }
-
- uel = curundo;
- if (uel == NULL) {
- fprintf(stderr, "No undo buffer to save recovery file\n");
- return false;
- }
-
- /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK,
- * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks.
- */
-
- oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC;
-#ifdef O_NOFOLLOW
- /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */
- oflags |= O_NOFOLLOW;
-#else
- /* TODO(sergey): How to deal with symlinks on windows? */
-# ifndef _MSC_VER
-# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103"
-# endif
-#endif
- file = BLI_open(filename, oflags, 0666);
-
- if (file == -1) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- filename, errno ? strerror(errno) : "Unknown error opening file");
- return false;
- }
-
- for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) {
- if (write(file, chunk->buf, chunk->size) != chunk->size) {
- break;
- }
- }
-
- close(file);
-
- if (chunk) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- filename, errno ? strerror(errno) : "Unknown error writing file");
- return false;
- }
- return true;
-}
-
-/* sets curscene */
-Main *BKE_undo_get_main(Scene **r_scene)
-{
- Main *mainp = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
-
- if (bfd) {
- mainp = bfd->main;
- if (r_scene) {
- *r_scene = bfd->curscene;
- }
-
- MEM_freeN(bfd);
- }
-
- return mainp;
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Partial `.blend` file save.
- * \{ */
-
-void BKE_blendfile_write_partial_begin(Main *bmain_src)
-{
- BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
-}
-
-void BKE_blendfile_write_partial_tag_ID(ID *id, bool set)
-{
- if (set) {
- id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
- }
- else {
- id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
- }
-}
-
-static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
-{
- if (vid) {
- ID *id = vid;
- /* only tag for need-expand if not done, prevents eternal loops */
- if ((id->tag & LIB_TAG_DOIT) == 0)
- id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
- }
-}
-
-/**
- * \return Success.
- */
-bool BKE_blendfile_write_partial(
- Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
-{
- Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
- ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
- int a, retval;
-
- void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
-
- if (write_flags & G_FILE_RELATIVE_REMAP) {
- path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
- }
-
- BLO_main_expander(blendfile_write_partial_cb);
- BLO_expand_main(NULL, bmain_src);
-
- /* move over all tagged blocks */
- set_listbasepointers(bmain_src, lbarray_src);
- a = set_listbasepointers(bmain_dst, lbarray_dst);
- while (a--) {
- ID *id, *nextid;
- ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
-
- for (id = lb_src->first; id; id = nextid) {
- nextid = id->next;
- if (id->tag & LIB_TAG_DOIT) {
- BLI_remlink(lb_src, id);
- BLI_addtail(lb_dst, id);
- }
- }
- }
-
-
- /* save the buffer */
- retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
-
- /* move back the main, now sorted again */
- set_listbasepointers(bmain_src, lbarray_dst);
- a = set_listbasepointers(bmain_dst, lbarray_src);
- while (a--) {
- ID *id;
- ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
-
- while ((id = BLI_pophead(lb_src))) {
- BLI_addtail(lb_dst, id);
- id_sort_by_name(lb_dst, id);
- }
- }
-
- MEM_freeN(bmain_dst);
-
- if (path_list_backup) {
- BKE_bpath_list_restore(bmain_src, path_list_flag, path_list_backup);
- BKE_bpath_list_free(path_list_backup);
- }
-
- return retval;
-}
-
-void BKE_blendfile_write_partial_end(Main *bmain_src)
-{
- BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Copy/Paste `.blend`, partial saves.
- * \{ */
-
-void BKE_copybuffer_begin(Main *bmain_src)
-{
- BKE_blendfile_write_partial_begin(bmain_src);
-}
-
-void BKE_copybuffer_tag_ID(ID *id)
-{
- BKE_blendfile_write_partial_tag_ID(id, true);
-}
-
-/**
- * \return Success.
- */
-bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
-{
- const int write_flags = G_FILE_RELATIVE_REMAP;
-
- bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
-
- BKE_blendfile_write_partial_end(bmain_src);
-
- return retval;
-}
-
-/**
- * \return Success.
- */
-bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, ReportList *reports)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- Main *mainl = NULL;
- Library *lib;
- BlendHandle *bh;
-
- bh = BLO_blendhandle_from_file(libname, reports);
-
- if (bh == NULL) {
- /* error reports will have been made by BLO_blendhandle_from_file() */
- return false;
- }
-
- BKE_scene_base_deselect_all(scene);
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &bh, libname);
-
- BLO_library_link_copypaste(mainl, bh);
-
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
-
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* append, rather than linking */
- lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, true, false);
-
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DAG_relations_tag_update(bmain);
-
- BLO_blendhandle_close(bh);
- /* remove library... */
-
- return true;
-}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
new file mode 100644
index 00000000000..ad01fac2144
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -0,0 +1,143 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blender_copybuffer.c
+ * \ingroup bke
+ *
+ * Used for copy/paste operator, (using a temporary file).
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_callbacks.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_moviecache.h"
+
+#include "BKE_blender_copybuffer.h" /* own include */
+#include "BKE_blendfile.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+#include "IMB_colormanagement.h"
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Copy/Paste `.blend`, partial saves.
+ * \{ */
+
+void BKE_copybuffer_begin(Main *bmain_src)
+{
+ BKE_blendfile_write_partial_begin(bmain_src);
+}
+
+void BKE_copybuffer_tag_ID(ID *id)
+{
+ BKE_blendfile_write_partial_tag_ID(id, true);
+}
+
+/**
+ * \return Success.
+ */
+bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
+{
+ const int write_flags = G_FILE_RELATIVE_REMAP;
+
+ bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
+
+ BKE_blendfile_write_partial_end(bmain_src);
+
+ return retval;
+}
+
+/**
+ * \return Success.
+ */
+bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, ReportList *reports)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Main *mainl = NULL;
+ Library *lib;
+ BlendHandle *bh;
+
+ bh = BLO_blendhandle_from_file(libname, reports);
+
+ if (bh == NULL) {
+ /* error reports will have been made by BLO_blendhandle_from_file() */
+ return false;
+ }
+
+ BKE_scene_base_deselect_all(scene);
+
+ /* tag everything, all untagged data can be made local
+ * its also generally useful to know what is new
+ *
+ * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
+
+ BLO_library_link_copypaste(mainl, bh);
+
+ BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+
+ /* mark all library linked objects to be updated */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* append, rather than linking */
+ lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
+ BKE_library_make_local(bmain, lib, true, false);
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_relations_tag_update(bmain);
+
+ BLO_blendhandle_close(bh);
+ /* remove library... */
+
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
new file mode 100644
index 00000000000..ca0a1b91cea
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -0,0 +1,393 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blender_undo.c
+ * \ingroup bke
+ *
+ * Blend file undo (known as 'Global Undo').
+ * DNA level diffing for undo.
+ */
+
+#ifndef _WIN32
+# include <unistd.h> // for read close
+#else
+# include <io.h> // for open close read
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h> /* for open */
+#include <errno.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_moviecache.h"
+
+#include "BKE_blender_undo.h" /* own include */
+#include "BKE_blendfile.h"
+#include "BKE_appdir.h"
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "RE_pipeline.h"
+
+#include "BLO_undofile.h"
+#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
+ * \{ */
+
+#define UNDO_DISK 0
+
+typedef struct UndoElem {
+ struct UndoElem *next, *prev;
+ char str[FILE_MAX];
+ char name[BKE_UNDO_STR_MAX];
+ MemFile memfile;
+ uintptr_t undosize;
+} UndoElem;
+
+static ListBase undobase = {NULL, NULL};
+static UndoElem *curundo = NULL;
+
+
+static int read_undosave(bContext *C, UndoElem *uel)
+{
+ char mainstr[sizeof(G.main->name)];
+ 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));
+
+ BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
+
+ fileflags = G.fileflags;
+ G.fileflags |= G_FILE_NO_UI;
+
+ if (UNDO_DISK)
+ success = (BKE_blendfile_read(C, uel->str, NULL) != BKE_BLENDFILE_READ_FAIL);
+ else
+ success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL);
+
+ /* restore */
+ BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
+ G.fileflags = fileflags;
+
+ if (success) {
+ /* important not to update time here, else non keyed tranforms are lost */
+ DAG_on_visible_update(G.main, false);
+ }
+
+ return success;
+}
+
+/* name can be a dynamic string */
+void BKE_undo_write(bContext *C, const char *name)
+{
+ uintptr_t maxmem, totmem, memused;
+ int nr /*, success */ /* UNUSED */;
+ UndoElem *uel;
+
+ if ((U.uiflag & USER_GLOBALUNDO) == 0) {
+ return;
+ }
+
+ if (U.undosteps == 0) {
+ return;
+ }
+
+ /* remove all undos after (also when curundo == NULL) */
+ while (undobase.last != curundo) {
+ uel = undobase.last;
+ BLI_remlink(&undobase, uel);
+ BLO_memfile_free(&uel->memfile);
+ MEM_freeN(uel);
+ }
+
+ /* make new */
+ curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file");
+ BLI_strncpy(uel->name, name, sizeof(uel->name));
+ BLI_addtail(&undobase, uel);
+
+ /* and limit amount to the maximum */
+ nr = 0;
+ uel = undobase.last;
+ while (uel) {
+ nr++;
+ if (nr == U.undosteps) break;
+ uel = uel->prev;
+ }
+ if (uel) {
+ while (undobase.first != uel) {
+ UndoElem *first = undobase.first;
+ BLI_remlink(&undobase, first);
+ /* the merge is because of compression */
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
+ MEM_freeN(first);
+ }
+ }
+
+
+ /* disk save version */
+ if (UNDO_DISK) {
+ static int counter = 0;
+ char filepath[FILE_MAX];
+ char numstr[32];
+ int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */
+
+ /* calculate current filepath */
+ counter++;
+ counter = counter % U.undosteps;
+
+ BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
+ BLI_make_file_string("/", filepath, BKE_tempdir_session(), numstr);
+
+ /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
+
+ BLI_strncpy(curundo->str, filepath, sizeof(curundo->str));
+ }
+ else {
+ MemFile *prevfile = NULL;
+
+ if (curundo->prev) prevfile = &(curundo->prev->memfile);
+
+ memused = MEM_get_memory_in_use();
+ /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags);
+ curundo->undosize = MEM_get_memory_in_use() - memused;
+ }
+
+ if (U.undomemory != 0) {
+ /* limit to maximum memory (afterwards, we can't know in advance) */
+ totmem = 0;
+ maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024;
+
+ /* keep at least two (original + other) */
+ uel = undobase.last;
+ while (uel && uel->prev) {
+ totmem += uel->undosize;
+ if (totmem > maxmem) break;
+ uel = uel->prev;
+ }
+
+ if (uel) {
+ if (uel->prev && uel->prev->prev)
+ uel = uel->prev;
+
+ while (undobase.first != uel) {
+ UndoElem *first = undobase.first;
+ BLI_remlink(&undobase, first);
+ /* the merge is because of compression */
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
+ MEM_freeN(first);
+ }
+ }
+ }
+}
+
+/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
+void BKE_undo_step(bContext *C, int step)
+{
+
+ if (step == 0) {
+ read_undosave(C, curundo);
+ }
+ else if (step == 1) {
+ /* curundo should never be NULL, after restart or load file it should call undo_save */
+ if (curundo == NULL || curundo->prev == NULL) {
+ // XXX error("No undo available");
+ }
+ else {
+ if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
+ curundo = curundo->prev;
+ read_undosave(C, curundo);
+ }
+ }
+ else {
+ /* curundo has to remain current situation! */
+
+ if (curundo == NULL || curundo->next == NULL) {
+ // XXX error("No redo available");
+ }
+ else {
+ read_undosave(C, curundo->next);
+ curundo = curundo->next;
+ if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name);
+ }
+ }
+}
+
+void BKE_undo_reset(void)
+{
+ UndoElem *uel;
+
+ uel = undobase.first;
+ while (uel) {
+ BLO_memfile_free(&uel->memfile);
+ uel = uel->next;
+ }
+
+ BLI_freelistN(&undobase);
+ curundo = NULL;
+}
+
+/* based on index nr it does a restore */
+void BKE_undo_number(bContext *C, int nr)
+{
+ curundo = BLI_findlink(&undobase, nr);
+ BKE_undo_step(C, 0);
+}
+
+/* go back to the last occurance of name in stack */
+void BKE_undo_name(bContext *C, const char *name)
+{
+ UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
+
+ if (uel && uel->prev) {
+ curundo = uel->prev;
+ BKE_undo_step(C, 0);
+ }
+}
+
+/* name optional */
+bool BKE_undo_is_valid(const char *name)
+{
+ if (name) {
+ UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
+ return uel && uel->prev;
+ }
+
+ return undobase.last != undobase.first;
+}
+
+/* get name of undo item, return null if no item with this index */
+/* if active pointer, set it to 1 if true */
+const char *BKE_undo_get_name(int nr, bool *r_active)
+{
+ UndoElem *uel = BLI_findlink(&undobase, nr);
+
+ if (r_active) *r_active = false;
+
+ if (uel) {
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
+ return uel->name;
+ }
+ return NULL;
+}
+
+/**
+ * Saves .blend using undo buffer.
+ *
+ * \return success.
+ */
+bool BKE_undo_save_file(const char *filename)
+{
+ UndoElem *uel;
+ MemFileChunk *chunk;
+ int file, oflags;
+
+ if ((U.uiflag & USER_GLOBALUNDO) == 0) {
+ return false;
+ }
+
+ uel = curundo;
+ if (uel == NULL) {
+ fprintf(stderr, "No undo buffer to save recovery file\n");
+ return false;
+ }
+
+ /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK,
+ * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks.
+ */
+
+ oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC;
+#ifdef O_NOFOLLOW
+ /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */
+ oflags |= O_NOFOLLOW;
+#else
+ /* TODO(sergey): How to deal with symlinks on windows? */
+# ifndef _MSC_VER
+# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103"
+# endif
+#endif
+ file = BLI_open(filename, oflags, 0666);
+
+ if (file == -1) {
+ fprintf(stderr, "Unable to save '%s': %s\n",
+ filename, errno ? strerror(errno) : "Unknown error opening file");
+ return false;
+ }
+
+ for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) {
+ if (write(file, chunk->buf, chunk->size) != chunk->size) {
+ break;
+ }
+ }
+
+ close(file);
+
+ if (chunk) {
+ fprintf(stderr, "Unable to save '%s': %s\n",
+ filename, errno ? strerror(errno) : "Unknown error writing file");
+ return false;
+ }
+ return true;
+}
+
+/* sets curscene */
+Main *BKE_undo_get_main(Scene **r_scene)
+{
+ Main *mainp = NULL;
+ BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
+
+ if (bfd) {
+ mainp = bfd->main;
+ if (r_scene) {
+ *r_scene = bfd->curscene;
+ }
+
+ MEM_freeN(bfd);
+ }
+
+ return mainp;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
new file mode 100644
index 00000000000..bedf262541f
--- /dev/null
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -0,0 +1,569 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blendfile.c
+ * \ingroup bke
+ *
+ * High level `.blend` file read/write,
+ * and functions for writing *partial* files (only selected data-blocks).
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
+
+#include "IMB_colormanagement.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blender.h"
+#include "BKE_blender_version.h"
+#include "BKE_blendfile.h"
+#include "BKE_bpath.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+#include "RNA_access.h"
+
+#include "RE_pipeline.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name High Level `.blend` file read/write.
+ * \{ */
+
+static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
+{
+ strcpy(path_dst, path_src);
+ BLI_path_native_slash(path_dst);
+ return !STREQ(path_dst, path_src);
+}
+
+/* make sure path names are correct for OS */
+static void clean_paths(Main *main)
+{
+ Scene *scene;
+
+ BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
+
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ BLI_path_native_slash(scene->r.pic);
+ }
+}
+
+static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
+{
+ wmWindow *win;
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen->scene == scene) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Context matching, handle no-ui case
+ *
+ * \note this is called on Undo so any slow conversion functions here
+ * should be avoided or check (mode != LOAD_UNDO).
+ *
+ * \param bfd: Blend file data, freed by this function on exit.
+ * \param filepath: File path or identifier.
+ */
+static void setup_app_data(
+ bContext *C, BlendFileData *bfd,
+ const char *filepath, ReportList *reports)
+{
+ Scene *curscene = NULL;
+ const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
+ enum {
+ LOAD_UI = 1,
+ LOAD_UI_OFF,
+ LOAD_UNDO,
+ } mode;
+
+ if (BLI_listbase_is_empty(&bfd->main->screen)) {
+ mode = LOAD_UNDO;
+ }
+ else if (G.fileflags & G_FILE_NO_UI) {
+ mode = LOAD_UI_OFF;
+ }
+ else {
+ mode = LOAD_UI;
+ }
+
+ if (mode != LOAD_UNDO) {
+ /* may happen with library files */
+ if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
+ BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ mode = LOAD_UI_OFF;
+ }
+ }
+
+ /* Free all render results, without this stale data gets displayed after loading files */
+ if (mode != LOAD_UNDO) {
+ RE_FreeAllRenderResults();
+ }
+
+ /* Only make filepaths compatible when loading for real (not undo) */
+ if (mode != LOAD_UNDO) {
+ clean_paths(bfd->main);
+ }
+
+ /* XXX here the complex windowmanager matching */
+
+ /* no load screens? */
+ if (mode != LOAD_UI) {
+ /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
+ * as long as the scene associated with the undo operation is visible in one of the open windows.
+ *
+ * - 'curscreen->scene' - scene the user is currently looking at.
+ * - 'bfd->curscene' - scene undo-step was created in.
+ *
+ * This means users can have 2+ windows open and undo in both without screens switching.
+ * But if they close one of the screens,
+ * undo will ensure that the scene being operated on will be activated
+ * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
+ * see: T43424
+ */
+ bScreen *curscreen = NULL;
+ bool track_undo_scene;
+
+ /* comes from readfile.c */
+ SWAP(ListBase, G.main->wm, bfd->main->wm);
+ SWAP(ListBase, G.main->screen, bfd->main->screen);
+
+ /* we re-use current screen */
+ curscreen = CTX_wm_screen(C);
+ /* but use new Scene pointer */
+ curscene = bfd->curscene;
+
+ track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
+
+ if (curscene == NULL) {
+ curscene = bfd->main->scene.first;
+ }
+ /* empty file, we add a scene to make Blender work */
+ if (curscene == NULL) {
+ curscene = BKE_scene_add(bfd->main, "Empty");
+ }
+
+ if (track_undo_scene) {
+ /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
+ * replace it with 'curscene' if its needed */
+ }
+ else {
+ /* and we enforce curscene to be in current screen */
+ if (curscreen) {
+ /* can run in bgmode */
+ curscreen->scene = curscene;
+ }
+ }
+
+ /* BKE_blender_globals_clear will free G.main, here we can still restore pointers */
+ blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
+ /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
+ if (curscreen) {
+ curscene = curscreen->scene;
+ }
+
+ if (track_undo_scene) {
+ wmWindowManager *wm = bfd->main->wm.first;
+ if (wm_scene_is_visible(wm, bfd->curscene) == false) {
+ curscene = bfd->curscene;
+ curscreen->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen);
+ }
+ }
+ }
+
+ /* free G.main Main database */
+// CTX_wm_manager_set(C, NULL);
+ BKE_blender_globals_clear();
+
+ /* clear old property update cache, in case some old references are left dangling */
+ RNA_property_update_cache_free();
+
+ G.main = bfd->main;
+
+ CTX_data_main_set(C, G.main);
+
+ if (bfd->user) {
+
+ /* only here free userdef themes... */
+ BKE_blender_userdef_free();
+
+ U = *bfd->user;
+
+ /* Security issue: any blend file could include a USER block.
+ *
+ * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
+ * to load the preferences defined in the users home dir.
+ *
+ * This means we will never accidentally (or maliciously)
+ * enable scripts auto-execution by loading a '.blend' file.
+ */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+
+ MEM_freeN(bfd->user);
+ }
+
+ /* case G_FILE_NO_UI or no screens in file */
+ if (mode != LOAD_UI) {
+ /* leave entire context further unaltered? */
+ CTX_data_scene_set(C, curscene);
+ }
+ else {
+ G.fileflags = bfd->fileflags;
+ CTX_wm_manager_set(C, G.main->wm.first);
+ CTX_wm_screen_set(C, bfd->curscreen);
+ CTX_data_scene_set(C, bfd->curscene);
+ CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, NULL);
+ CTX_wm_menu_set(C, NULL);
+ curscene = bfd->curscene;
+ }
+
+ /* this can happen when active scene was lib-linked, and doesn't exist anymore */
+ if (CTX_data_scene(C) == NULL) {
+ /* in case we don't even have a local scene, add one */
+ if (!G.main->scene.first)
+ BKE_scene_add(G.main, "Empty");
+
+ CTX_data_scene_set(C, G.main->scene.first);
+ CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ curscene = CTX_data_scene(C);
+ }
+
+ BLI_assert(curscene == CTX_data_scene(C));
+
+
+ /* special cases, override loaded flags: */
+ if (G.f != bfd->globalf) {
+ const int flags_keep = (G_SWAP_EXCHANGE | G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
+ bfd->globalf = (bfd->globalf & ~flags_keep) | (G.f & flags_keep);
+ }
+
+
+ G.f = bfd->globalf;
+
+#ifdef WITH_PYTHON
+ /* let python know about new main */
+ BPY_context_update(C);
+#endif
+
+ /* FIXME: this version patching should really be part of the file-reading code,
+ * but we still get too many unrelated data-corruption crashes otherwise... */
+ if (G.main->versionfile < 250)
+ do_versions_ipos_to_animato(G.main);
+
+ G.main->recovered = 0;
+
+ /* startup.blend or recovered startup */
+ if (bfd->filename[0] == 0) {
+ G.main->name[0] = 0;
+ }
+ else if (recover && G.relbase_valid) {
+ /* in case of autosave or quit.blend, use original filename instead
+ * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
+ filepath = bfd->filename;
+ G.main->recovered = 1;
+
+ /* these are the same at times, should never copy to the same location */
+ if (G.main->name != filepath)
+ BLI_strncpy(G.main->name, filepath, FILE_MAX);
+ }
+
+ /* baseflags, groups, make depsgraph, etc */
+ /* first handle case if other windows have different scenes visible */
+ if (mode == LOAD_UI) {
+ wmWindowManager *wm = G.main->wm.first;
+
+ if (wm) {
+ wmWindow *win;
+
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen && win->screen->scene) /* zealous check... */
+ if (win->screen->scene != curscene)
+ BKE_scene_set_background(G.main, win->screen->scene);
+ }
+ }
+ }
+ BKE_scene_set_background(G.main, curscene);
+
+ if (mode != LOAD_UNDO) {
+ RE_FreeAllPersistentData();
+ IMB_colormanagement_check_file_config(G.main);
+ }
+
+ MEM_freeN(bfd);
+
+}
+
+static int handle_subversion_warning(Main *main, ReportList *reports)
+{
+ if (main->minversionfile > BLENDER_VERSION ||
+ (main->minversionfile == BLENDER_VERSION &&
+ main->minsubversionfile > BLENDER_SUBVERSION))
+ {
+ BKE_reportf(reports, RPT_ERROR, "File written by newer Blender binary (%d.%d), expect loss of data!",
+ main->minversionfile, main->minsubversionfile);
+ }
+
+ return 1;
+}
+
+int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
+{
+ BlendFileData *bfd;
+ int retval = BKE_BLENDFILE_READ_OK;
+
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
+ printf("read blend: %s\n", filepath);
+
+ bfd = BLO_read_from_file(filepath, reports);
+ if (bfd) {
+ if (bfd->user) retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+
+ if (0 == handle_subversion_warning(bfd->main, reports)) {
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ bfd = NULL;
+ retval = BKE_BLENDFILE_READ_FAIL;
+ }
+ else {
+ setup_app_data(C, bfd, filepath, reports);
+ }
+ }
+ else
+ BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
+
+ return (bfd ? retval : BKE_BLENDFILE_READ_FAIL);
+}
+
+bool BKE_blendfile_read_from_memory(
+ bContext *C, const void *filebuf, int filelength,
+ ReportList *reports, bool update_defaults)
+{
+ BlendFileData *bfd;
+
+ bfd = BLO_read_from_memory(filebuf, filelength, reports);
+ if (bfd) {
+ if (update_defaults)
+ BLO_update_defaults_startup_blend(bfd->main);
+ setup_app_data(C, bfd, "<memory2>", reports);
+ }
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
+
+ return (bfd != NULL);
+}
+
+/* memfile is the undo buffer */
+bool BKE_blendfile_read_from_memfile(
+ bContext *C, struct MemFile *memfile,
+ ReportList *reports)
+{
+ BlendFileData *bfd;
+
+ bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports);
+ if (bfd) {
+ /* remove the unused screens and wm */
+ while (bfd->main->wm.first)
+ BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
+ while (bfd->main->screen.first)
+ BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
+
+ setup_app_data(C, bfd, "<memory1>", reports);
+ }
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
+
+ return (bfd != NULL);
+}
+
+/* only read the userdef from a .blend */
+int BKE_blendfile_read_userdef(const char *filepath, ReportList *reports)
+{
+ BlendFileData *bfd;
+ int retval = BKE_BLENDFILE_READ_FAIL;
+
+ bfd = BLO_read_from_file(filepath, reports);
+ if (bfd) {
+ if (bfd->user) {
+ retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+
+ /* only here free userdef themes... */
+ BKE_blender_userdef_free();
+
+ U = *bfd->user;
+ MEM_freeN(bfd->user);
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
+
+ return retval;
+}
+
+/* only write the userdef in a .blend */
+int BKE_blendfile_write_userdef(const char *filepath, ReportList *reports)
+{
+ Main *mainb = MEM_callocN(sizeof(Main), "empty main");
+ int retval = 0;
+
+ if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) {
+ retval = 1;
+ }
+
+ MEM_freeN(mainb);
+
+ return retval;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Partial `.blend` file save.
+ * \{ */
+
+void BKE_blendfile_write_partial_begin(Main *bmain_src)
+{
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
+}
+
+void BKE_blendfile_write_partial_tag_ID(ID *id, bool set)
+{
+ if (set) {
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
+ }
+}
+
+static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
+{
+ if (vid) {
+ ID *id = vid;
+ /* only tag for need-expand if not done, prevents eternal loops */
+ if ((id->tag & LIB_TAG_DOIT) == 0)
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+
+ if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0)
+ id->lib->id.tag |= LIB_TAG_DOIT;
+ }
+}
+
+/**
+ * \return Success.
+ */
+bool BKE_blendfile_write_partial(
+ Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
+{
+ Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
+ ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
+ int a, retval;
+
+ void *path_list_backup = NULL;
+ const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+
+ if (write_flags & G_FILE_RELATIVE_REMAP) {
+ path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
+ }
+
+ BLO_main_expander(blendfile_write_partial_cb);
+ BLO_expand_main(NULL, bmain_src);
+
+ /* move over all tagged blocks */
+ set_listbasepointers(bmain_src, lbarray_src);
+ a = set_listbasepointers(bmain_dst, lbarray_dst);
+ while (a--) {
+ ID *id, *nextid;
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
+
+ for (id = lb_src->first; id; id = nextid) {
+ nextid = id->next;
+ if (id->tag & LIB_TAG_DOIT) {
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ }
+ }
+
+
+ /* save the buffer */
+ retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
+
+ /* move back the main, now sorted again */
+ set_listbasepointers(bmain_src, lbarray_dst);
+ a = set_listbasepointers(bmain_dst, lbarray_src);
+ while (a--) {
+ ID *id;
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
+
+ while ((id = BLI_pophead(lb_src))) {
+ BLI_addtail(lb_dst, id);
+ id_sort_by_name(lb_dst, id);
+ }
+ }
+
+ MEM_freeN(bmain_dst);
+
+ if (path_list_backup) {
+ BKE_bpath_list_restore(bmain_src, path_list_flag, path_list_backup);
+ BKE_bpath_list_free(path_list_backup);
+ }
+
+ return retval;
+}
+
+void BKE_blendfile_write_partial_end(Main *bmain_src)
+{
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index abba61310a4..7821946eb6e 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -151,10 +151,10 @@ static void mesh_looptri_nearest_point(void *userdata, int index, const float co
}
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void editmesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- BMEditMesh *em = data->em_evil;
+ const BVHTreeFromEditMesh *data = userdata;
+ BMEditMesh *em = data->em;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
@@ -240,10 +240,10 @@ static void mesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay
}
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void editmesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- BMEditMesh *em = data->em_evil;
+ const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
+ BMEditMesh *em = data->em;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
@@ -296,7 +296,7 @@ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3
/* Helper, does all the point-spherecast work actually. */
static void mesh_verts_spherecast_do(
- const BVHTreeFromMesh *UNUSED(data), int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
+ int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
float dist;
const float *r1;
@@ -314,6 +314,14 @@ static void mesh_verts_spherecast_do(
}
}
+static void editmesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ const BVHTreeFromEditMesh *data = userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+
+ mesh_verts_spherecast_do(index, eve->co, ray, hit);
+}
+
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
@@ -321,7 +329,7 @@ static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *r
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const float *v = data->vert[index].co;
- mesh_verts_spherecast_do(data, index, v, ray, hit);
+ mesh_verts_spherecast_do(index, v, ray, hit);
}
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
@@ -341,7 +349,7 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
/* In case we get a zero-length edge, handle it as a point! */
if (equals_v3v3(v1, v2)) {
- mesh_verts_spherecast_do(data, index, v1, ray, hit);
+ mesh_verts_spherecast_do(index, v1, ray, hit);
return;
}
@@ -380,78 +388,64 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
/** \name Vertex Builder
* \{ */
-static BVHTree *bvhtree_from_mesh_verts_create_tree(
+static BVHTree *bvhtree_from_editmesh_verts_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const int *index_array,
- MVert *vert, const int numVerts,
- BLI_bitmap *mask, int numVerts_active)
+ BMEditMesh *em, const int verts_num,
+ const BLI_bitmap *verts_mask, int verts_num_active)
{
BVHTree *tree = NULL;
- BMVert *eve = NULL;
int i;
- int index = 0;
- if (em != NULL) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
- if (vert) {
- if (mask && numVerts_active < 0) {
- numVerts_active = 0;
- for (i = 0; i < numVerts; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- if (index == ORIGINDEX_NONE) {
- continue;
- }
- }
- else {
- index = i;
- }
-
- eve = BM_vert_at_index(em->bm, index);
- if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eve, BM_ELEM_SELECT))
- {
- continue;
- }
- }
- numVerts_active++;
- }
+ else {
+ verts_num_active = verts_num;
+ }
+
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ BMIter iter;
+ BMVert *eve;
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
+ BLI_bvhtree_insert(tree, i, eve->co, 1);
}
- else if (!mask) {
- numVerts_active = numVerts;
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static BVHTree *bvhtree_from_mesh_verts_create_tree(
+ float epsilon, int tree_type, int axis,
+ MVert *vert, const int verts_num,
+ const BLI_bitmap *verts_mask, int verts_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+ if (vert) {
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
}
- tree = BLI_bvhtree_new(numVerts_active, epsilon, tree_type, axis);
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
if (tree) {
- for (i = 0; i < numVerts; i++) {
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
+ for (i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
continue;
}
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- if (index == ORIGINDEX_NONE) {
- continue;
- }
- }
- else {
- index = i;
- }
-
- eve = BM_vert_at_index(em->bm, index);
- if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eve, BM_ELEM_SELECT))
- {
- continue;
- }
- }
BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
-
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -488,17 +482,51 @@ static void bvhtree_from_mesh_verts_setup_data(
}
}
+/* Builds a bvh tree where nodes are the vertices of the given em */
+BVHTree *bvhtree_from_editmesh_verts_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *verts_mask, int verts_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ int vert_num = em->bm->totvert;
+
+ BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
+ epsilon, tree_type, axis,
+ em, vert_num, verts_mask, verts_num_active);
+
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL;
+ data->raycast_callback = editmesh_verts_spherecast;
+ data->nearest_to_ray_callback = NULL;
+ }
+
+ return tree;
+}
+BVHTree *bvhtree_from_editmesh_verts(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+}
+
+
/* Builds a bvh tree where nodes are the vertices of the given dm */
-BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_verts(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ? BVHTREE_FROM_VERTS_EDITMESH_SNAP : BVHTREE_FROM_VERTS;
BVHTree *tree;
MVert *vert;
bool vert_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -506,26 +534,20 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
if (tree == NULL) {
- int vert_num, *index_array = NULL;
- if (em != NULL) {
- vert_num = em->bm->totvert;
- index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
- }
- else {
- vert_num = dm->getNumVerts(dm);
- BLI_assert(vert_num != 0);
- }
+
+ int vert_num = dm->getNumVerts(dm);
+ BLI_assert(vert_num != 0);
+
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis,
- em, index_array,
vert, vert_num, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -544,14 +566,15 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e
* 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 numVerts_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
+ * \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(
- BVHTreeFromMesh *data, MVert *vert, const int numVerts, const bool vert_allocated,
- BLI_bitmap *mask, int numVerts_active,
+ BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated,
+ const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
- BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, NULL, NULL, vert, numVerts, mask, numVerts_active);
+ BVHTree *tree = bvhtree_from_mesh_verts_create_tree(
+ epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
@@ -568,7 +591,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(
* \{ */
/* Builds a bvh tree where nodes are the edges of the given dm */
-BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_edges(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
BVHTree *tree;
MVert *vert;
@@ -576,7 +601,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
bool vert_allocated, edge_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -585,7 +610,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
int i;
int numEdges = dm->getNumEdges(dm);
@@ -655,109 +680,41 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const bool em_all,
- MVert *vert, MFace *face, const int numFaces,
- BLI_bitmap *mask, int numFaces_active)
+ MVert *vert, MFace *face, const int faces_num,
+ const BLI_bitmap *faces_mask, int faces_num_active)
{
BVHTree *tree = NULL;
int i;
- if (numFaces) {
- if (mask && numFaces_active < 0) {
- numFaces_active = 0;
- for (i = 0; i < numFaces; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- numFaces_active++;
- }
- }
+ if (faces_num) {
+ if (faces_mask) {
+ BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
}
- else if (!mask) {
- numFaces_active = numFaces;
+ else {
+ faces_num_active = faces_num;
}
/* Create a bvh-tree of the given target */
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
- tree = BLI_bvhtree_new(numFaces_active, epsilon, tree_type, axis);
+ tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
if (tree) {
- if (em) {
- const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
-
- /* avoid double-up on face searches for quads-ngons */
- bool insert_prev = false;
- BMFace *f_prev = NULL;
-
- /* data->em_evil is only set for snapping, and only for the mesh of the object
- * which is currently open in edit mode. When set, the bvhtree should not contain
- * faces that will interfere with snapping (e.g. faces that are hidden/selected
- * or faces that have selected verts). */
-
- /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
- * and/or selected. Even if the faces themselves are not selected for the snapped
- * transform, having a vertex selected means the face (and thus it's tessellated
- * triangles) will be moving and will not be a good snap targets. */
- for (i = 0; i < numFaces; i++) {
- const BMLoop **ltri = looptris[i];
- BMFace *f = ltri[0]->f;
- bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true;
-
- /* Start with the assumption the triangle should be included for snapping. */
- if (f == f_prev) {
- insert = insert_prev;
- }
- else if (insert) {
- if (em_all) {
- /* pass */
- }
- else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- /* Don't insert triangles tessellated from faces that are hidden or selected */
- insert = false;
- }
- else {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
- /* Don't insert triangles tessellated from faces that have any selected verts */
- insert = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* skip if face doesn't change */
- f_prev = f;
- insert_prev = insert;
+ if (vert && face) {
+ for (i = 0; i < faces_num; i++) {
+ float co[4][3];
+ if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) {
+ continue;
}
- if (insert) {
- /* No reason found to block hit-testing the triangle for snap, so insert it now.*/
- float co[3][3];
- copy_v3_v3(co[0], ltri[0]->v->co);
- copy_v3_v3(co[1], ltri[1]->v->co);
- copy_v3_v3(co[2], ltri[2]->v->co);
+ copy_v3_v3(co[0], vert[face[i].v1].co);
+ copy_v3_v3(co[1], vert[face[i].v2].co);
+ copy_v3_v3(co[2], vert[face[i].v3].co);
+ if (face[i].v4)
+ copy_v3_v3(co[3], vert[face[i].v4].co);
- BLI_bvhtree_insert(tree, i, co[0], 3);
- }
- }
- }
- else {
- if (vert && face) {
- for (i = 0; i < numFaces; i++) {
- float co[4][3];
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
- continue;
- }
-
- copy_v3_v3(co[0], vert[face[i].v1].co);
- copy_v3_v3(co[1], vert[face[i].v2].co);
- copy_v3_v3(co[2], vert[face[i].v3].co);
- if (face[i].v4)
- copy_v3_v3(co[3], vert[face[i].v4].co);
-
- BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
- }
+ BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
}
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == faces_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -766,33 +723,24 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
}
static void bvhtree_from_mesh_faces_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- float epsilon, BMEditMesh *em,
+ BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
MVert *vert, const bool vert_allocated,
MFace *face, const bool face_allocated)
{
memset(data, 0, sizeof(*data));
- data->em_evil = em;
if (tree) {
data->tree = tree;
data->cached = is_cached;
- if (em) {
- data->nearest_callback = editmesh_faces_nearest_point;
- data->raycast_callback = editmesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
- }
- else {
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
- }
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
+ data->nearest_to_ray_callback = NULL;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
data->sphere_radius = epsilon;
}
@@ -807,54 +755,37 @@ static void bvhtree_from_mesh_faces_setup_data(
}
/* Builds a bvh tree where nodes are the tesselated faces of the given dm */
-BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_faces(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ?
- (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
- BVHTREE_FROM_FACES;
BVHTree *tree;
MVert *vert = NULL;
MFace *face = NULL;
bool vert_allocated = false, face_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (em == NULL) {
- vert = DM_get_vert_array(dm, &vert_allocated);
- face = DM_get_tessface_array(dm, &face_allocated);
- }
+ vert = DM_get_vert_array(dm, &vert_allocated);
+ face = DM_get_tessface_array(dm, &face_allocated);
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
if (tree == NULL) {
- int numFaces;
-
- /* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
- if (em) {
- numFaces = em->tottri;
- }
- else {
- numFaces = dm->getNumTessFaces(dm);
- BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
- }
+ int numFaces = dm->getNumTessFaces(dm);
+ BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis,
- em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
vert, face, numFaces, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -864,7 +795,7 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e
}
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, em, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
return data->tree;
}
@@ -879,16 +810,16 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e
BVHTree *bvhtree_from_mesh_faces_ex(
BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated,
MFace *face, const int numFaces, const bool face_allocated,
- BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis)
+ const BLI_bitmap *faces_mask, int faces_num_active,
+ float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis,
- NULL, false,
vert, face, numFaces,
- mask, numFaces_active);
+ faces_mask, faces_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, NULL, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
return data->tree;
}
@@ -901,25 +832,19 @@ BVHTree *bvhtree_from_mesh_faces_ex(
/** \name LoopTri Face Builder
* \{ */
-static BVHTree *bvhtree_from_mesh_looptri_create_tree(
+static BVHTree *bvhtree_from_editmesh_looptri_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const bool em_all,
- const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
- BLI_bitmap *mask, int looptri_num_active)
+ BMEditMesh *em, const int looptri_num,
+ const BLI_bitmap *looptri_mask, int looptri_num_active)
{
BVHTree *tree = NULL;
int i;
if (looptri_num) {
- if (mask && looptri_num_active < 0) {
- looptri_num_active = 0;
- for (i = 0; i < looptri_num; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- looptri_num_active++;
- }
- }
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
}
- else if (!mask) {
+ else {
looptri_num_active = looptri_num;
}
@@ -930,52 +855,13 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
if (em) {
const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
- /* avoid double-up on face searches for quads-ngons */
- bool insert_prev = false;
- BMFace *f_prev = NULL;
-
- /* data->em_evil is only set for snapping, and only for the mesh of the object
- * which is currently open in edit mode. When set, the bvhtree should not contain
- * faces that will interfere with snapping (e.g. faces that are hidden/selected
- * or faces that have selected verts). */
-
/* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
* and/or selected. Even if the faces themselves are not selected for the snapped
* transform, having a vertex selected means the face (and thus it's tessellated
* triangles) will be moving and will not be a good snap targets. */
for (i = 0; i < looptri_num; i++) {
const BMLoop **ltri = looptris[i];
- BMFace *f = ltri[0]->f;
- bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true;
-
- /* Start with the assumption the triangle should be included for snapping. */
- if (f == f_prev) {
- insert = insert_prev;
- }
- else if (insert) {
- if (em_all) {
- /* pass */
- }
- else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- /* Don't insert triangles tessellated from faces that are hidden or selected */
- insert = false;
- }
- else {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
- /* Don't insert triangles tessellated from faces that have any selected verts */
- insert = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* skip if face doesn't change */
- f_prev = f;
- insert_prev = insert;
- }
+ bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true;
if (insert) {
/* No reason found to block hit-testing the triangle for snap, so insert it now.*/
@@ -988,22 +874,49 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
}
}
}
- else {
- if (vert && looptri) {
- for (i = 0; i < looptri_num; i++) {
- float co[3][3];
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
- continue;
- }
+ BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
- copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
- copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
- copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
+ return tree;
+}
- BLI_bvhtree_insert(tree, i, co[0], 3);
+static BVHTree *bvhtree_from_mesh_looptri_create_tree(
+ float epsilon, int tree_type, int axis,
+ const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
+ const BLI_bitmap *looptri_mask, int looptri_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+
+ if (looptri_num) {
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+
+ /* Create a bvh-tree of the given target */
+ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
+ tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ if (vert && looptri) {
+ for (i = 0; i < looptri_num; i++) {
+ float co[3][3];
+ if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
+ continue;
}
+
+ copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
+ copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
+ copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
}
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -1012,36 +925,27 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
}
static void bvhtree_from_mesh_looptri_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- float epsilon, BMEditMesh *em,
+ BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
const MVert *vert, const bool vert_allocated,
const MLoop *mloop, const bool loop_allocated,
const MLoopTri *looptri, const bool looptri_allocated)
{
memset(data, 0, sizeof(*data));
- data->em_evil = em;
if (tree) {
data->tree = tree;
data->cached = is_cached;
- if (em) {
- data->nearest_callback = editmesh_faces_nearest_point;
- data->raycast_callback = editmesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
- }
- else {
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
- }
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
+ data->nearest_to_ray_callback = NULL;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
data->sphere_radius = epsilon;
}
@@ -1059,16 +963,52 @@ static void bvhtree_from_mesh_looptri_setup_data(
}
/**
+ * Builds a bvh tree where nodes are the looptri faces of the given bm
+ */
+BVHTree *bvhtree_from_editmesh_looptri_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *looptri_mask, int looptri_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ /* BMESH specific check that we have tessfaces,
+ * we _could_ tessellate here but rather not - campbell
+ *
+ * this assert checks we have tessfaces,
+ * if not caller should use DM_ensure_tessface() */
+
+ BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+
+ if (tree) {
+ data->tree = tree;
+ data->nearest_callback = editmesh_looptri_nearest_point;
+ data->raycast_callback = editmesh_looptri_spherecast;
+ data->nearest_to_ray_callback = NULL;
+ data->sphere_radius = 0.0f;
+ data->em = em;
+ }
+ return tree;
+}
+
+BVHTree *bvhtree_from_editmesh_looptri(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_looptri_ex(
+ data, em, NULL, -1,
+ epsilon, tree_type, axis);
+}
+
+/**
* Builds a bvh tree where nodes are the looptri faces of the given dm
*
* \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces
*/
-BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_looptri(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ?
- (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
- BVHTREE_FROM_LOOPTRI;
BVHTree *tree;
MVert *mvert = NULL;
MLoop *mloop = NULL;
@@ -1078,58 +1018,42 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float
bool looptri_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (em == NULL) {
- MPoly *mpoly;
- bool poly_allocated = false;
-
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mpoly = DM_get_poly_array(dm, &poly_allocated);
+ MPoly *mpoly;
+ bool poly_allocated = false;
- mloop = DM_get_loop_array(dm, &loop_allocated);
- looptri = DM_get_looptri_array(
- dm,
- mvert,
- mpoly, dm->getNumPolys(dm),
- mloop, dm->getNumLoops(dm),
- &looptri_allocated);
+ mvert = DM_get_vert_array(dm, &vert_allocated);
+ mpoly = DM_get_poly_array(dm, &poly_allocated);
- if (poly_allocated) {
- MEM_freeN(mpoly);
- }
+ mloop = DM_get_loop_array(dm, &loop_allocated);
+ looptri = DM_get_looptri_array(
+ dm,
+ mvert,
+ mpoly, dm->getNumPolys(dm),
+ mloop, dm->getNumLoops(dm),
+ &looptri_allocated);
+ if (poly_allocated) {
+ MEM_freeN(mpoly);
}
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
if (tree == NULL) {
- int looptri_num;
-
- /* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
- if (em) {
- looptri_num = em->tottri;
- }
- else {
- looptri_num = dm->getNumLoopTri(dm);
- BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
- }
+ int looptri_num = dm->getNumLoopTri(dm);
+ BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_looptri_create_tree(
epsilon, tree_type, axis,
- em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
mvert, mloop, looptri, looptri_num, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -1140,7 +1064,7 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_looptri_setup_data(
- data, tree, true, epsilon, em,
+ data, tree, true, epsilon,
mvert, vert_allocated,
mloop, loop_allocated,
looptri, looptri_allocated);
@@ -1153,18 +1077,17 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const struct MVert *vert, const bool vert_allocated,
const struct MLoop *mloop, const bool loop_allocated,
const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated,
- BLI_bitmap *mask, int looptri_num_active,
+ const BLI_bitmap *looptri_mask, int looptri_num_active,
float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_looptri_create_tree(
epsilon, tree_type, axis,
- NULL, false,
vert, mloop, looptri, looptri_num,
- mask, looptri_num_active);
+ looptri_mask, looptri_num_active);
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_looptri_setup_data(
- data, tree, false, epsilon, NULL,
+ data, tree, false, epsilon,
vert, vert_allocated,
mloop, loop_allocated,
looptri, looptri_allocated);
@@ -1175,6 +1098,15 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
/** \} */
+/* Frees data allocated by a call to bvhtree_from_editmesh_*. */
+void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
+{
+ if (data->tree) {
+ BLI_bvhtree_free(data->tree);
+ memset(data, 0, sizeof(*data));
+ }
+}
+
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
@@ -1215,32 +1147,46 @@ typedef struct BVHCacheItem {
} BVHCacheItem;
-static void bvhcacheitem_set_if_match(void *_cached, void *_search)
+/**
+ * Queries a bvhcache for the cache bvhtree of the request type
+ */
+BVHTree *bvhcache_find(BVHCache *cache, int type)
{
- BVHCacheItem *cached = (BVHCacheItem *)_cached;
- BVHCacheItem *search = (BVHCacheItem *)_search;
-
- if (search->type == cached->type) {
- search->tree = cached->tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->type == type) {
+ return item->tree;
+ }
+ cache = cache->next;
}
-}
+ return NULL;
+}
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
{
- BVHCacheItem item;
- item.type = type;
- item.tree = NULL;
-
- BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item);
- return item.tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->tree == tree) {
+ return true;
+ }
+ cache = cache->next;
+ }
+ return false;
}
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
+/**
+ * Inserts a BVHTree of the given type under the cache
+ * After that the caller no longer needs to worry when to free the BVHTree
+ * as that will be done when the cache is freed.
+ *
+ * A call to this assumes that there was no previous cached tree of the given type
+ */
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
assert(tree != NULL);
- assert(bvhcache_find(cache, type) == NULL);
+ assert(bvhcache_find(*cache_p, type) == NULL);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
assert(item != NULL);
@@ -1248,13 +1194,15 @@ void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
item->type = type;
item->tree = tree;
- BLI_linklist_prepend(cache, item);
+ BLI_linklist_prepend(cache_p, item);
}
-
-void bvhcache_init(BVHCache *cache)
+/**
+ * inits and frees a bvhcache
+ */
+void bvhcache_init(BVHCache **cache_p)
{
- *cache = NULL;
+ *cache_p = NULL;
}
static void bvhcacheitem_free(void *_item)
@@ -1266,10 +1214,10 @@ static void bvhcacheitem_free(void *_item)
}
-void bvhcache_free(BVHCache *cache)
+void bvhcache_free(BVHCache **cache_p)
{
- BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache = NULL;
+ BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
+ *cache_p = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 6fd756e2788..96bac2c2f41 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -76,6 +76,8 @@ void BKE_camera_init(Camera *cam)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
+ cam->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
@@ -904,7 +906,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha
/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
{
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
if (!is_multiview) {
return camera;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 519b7b44637..e6741657f47 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1049,11 +1049,13 @@ static void cdDM_drawMappedFacesGLSL(
numdata++;
}
}
- if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
+ for (b = 0; b < matconv[a].attribs.tottang; b++) {
+ if (matconv[a].attribs.tang[b].array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].size = 4;
+ matconv[a].datatypes[numdata].type = GL_FLOAT;
+ numdata++;
+ }
}
if (numdata != 0) {
matconv[a].numdata = numdata;
@@ -1105,11 +1107,13 @@ static void cdDM_drawMappedFacesGLSL(
offset += sizeof(unsigned char) * 4;
}
}
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
- offset += sizeof(float) * 4;
+ for (b = 0; b < matconv[i].attribs.tottang; b++) {
+ if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
+ const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
+ for (j = 0; j < mpoly->totloop; j++)
+ copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
+ offset += sizeof(float) * 4;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 7a2a4e09b3d..3e6df3ed77c 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -58,6 +58,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
+static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
@@ -369,6 +370,10 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
+
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW )
+ cloth_update_spring_lengths ( clmd, result );
+
cloth_update_springs( clmd );
// TIMEIT_START(cloth_step)
@@ -644,6 +649,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
{
return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) ||
(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) ||
+ (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) ||
(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)) &&
((clmd->sim_parms->vgroup_mass>0) ||
(clmd->sim_parms->vgroup_struct>0)||
@@ -684,6 +690,9 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
else
verts->goal= 0.0f;
+ /* Compute base cloth shrink weight */
+ verts->shrink_factor = 0.0f;
+
/* Reset vertex flags */
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
@@ -721,16 +730,14 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
}
}
-
+ }
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
if (clmd->sim_parms->vgroup_shrink > 0) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* linear interpolation between min and max shrink factor based on weight */
- verts->shrink_factor = clmd->sim_parms->shrink_min * (1.0f - dvert->dw[j].weight) + clmd->sim_parms->shrink_max * dvert->dw [j].weight;
+ /* used for linear interpolation between min and max shrink factor based on weight */
+ verts->shrink_factor = dvert->dw[j].weight;
}
}
- else {
- verts->shrink_factor = clmd->sim_parms->shrink_min;
- }
}
}
}
@@ -738,6 +745,23 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
+static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2)
+{
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
+ /* linear interpolation between min and max shrink factor based on weight */
+ float base = 1.0f - clmd->sim_parms->shrink_min;
+ float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+
+ float k1 = base + delta * verts[i1].shrink_factor;
+ float k2 = base + delta * verts[i2].shrink_factor;
+
+ /* Use geometrical mean to average two factors since it behaves better
+ for diagonals when a rectangle transforms into a trapezoid. */
+ return sqrtf(k1 * k2);
+ }
+ else
+ return 1.0f;
+}
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
{
@@ -795,11 +819,11 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
mul_m4_v3(ob->obmat, verts->x);
if ( shapekey_rest ) {
- verts->xrest= shapekey_rest[i];
+ copy_v3_v3(verts->xrest, shapekey_rest[i]);
mul_m4_v3(ob->obmat, verts->xrest);
}
else
- verts->xrest = verts->x;
+ copy_v3_v3(verts->xrest, verts->x);
}
/* no GUI interface yet */
@@ -811,6 +835,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
else
verts->goal= 0.0f;
+ verts->shrink_factor = 0.0f;
+
verts->flags = 0;
copy_v3_v3 ( verts->xold, verts->x );
copy_v3_v3 ( verts->xconst, verts->x );
@@ -1154,6 +1180,53 @@ static void cloth_update_springs( ClothModifierData *clmd )
cloth_hair_update_bending_targets(clmd);
}
+/* Update spring rest lenght, for dynamically deformable cloth */
+static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = cloth->springs;
+ unsigned int struct_springs = 0;
+ unsigned int i = 0;
+ unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ float shrink_factor;
+
+ clmd->sim_parms->avg_spring_len = 0.0f;
+
+ for (i = 0; i < mvert_num; i++) {
+ cloth->verts[i].avg_spring_len = 0.0f;
+ }
+
+ while (search) {
+ ClothSpring *spring = search->link;
+
+ if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) {
+ if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) )
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ else
+ shrink_factor = 1.0f;
+
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ }
+
+ if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) {
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ struct_springs++;
+ }
+
+ search = search->next;
+ }
+
+ if (struct_springs > 0)
+ clmd->sim_parms->avg_spring_len /= struct_springs;
+
+ for (i = 0; i < mvert_num; i++) {
+ if (cloth->verts[i].spring_count > 0)
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ }
+}
+
BLI_INLINE void cross_identity_v3(float r[3][3], const float v[3])
{
zero_m3(r);
@@ -1193,7 +1266,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
{
Cloth *cloth = clmd->clothObject;
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
- unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
+ unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
unsigned int i = 0;
unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
@@ -1237,19 +1310,19 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->type = CLOTH_SPRING_TYPE_SEWING;
}
else {
- if (clmd->sim_parms->vgroup_shrink > 0)
- shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f);
- else
- shrink_factor = 1.0f - clmd->sim_parms->shrink_min;
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
+
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].spring_count++;
+ cloth->verts[spring->kl].spring_count++;
+ struct_springs_real++;
}
- clmd->sim_parms->avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].avg_spring_len += spring->restlen;
- cloth->verts[spring->kl].avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].spring_count++;
- cloth->verts[spring->kl].spring_count++;
+
spring->flags = 0;
struct_springs++;
@@ -1261,11 +1334,12 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
- if (struct_springs > 0)
- clmd->sim_parms->avg_spring_len /= struct_springs;
+ if (struct_springs_real > 0)
+ clmd->sim_parms->avg_spring_len /= struct_springs_real;
for (i = 0; i < mvert_num; i++) {
- cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ if (cloth->verts[i].spring_count > 0)
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
}
// shear springs
@@ -1287,10 +1361,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
mloop[mpoly[i].loopstart + (j + 0)].v,
mloop[mpoly[i].loopstart + (j + 2)].v);
- if (clmd->sim_parms->vgroup_shrink > 0)
- shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f);
- else
- shrink_factor = 1.0f - clmd->sim_parms->shrink_min;
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->type = CLOTH_SPRING_TYPE_SHEAR;
spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
@@ -1334,7 +1405,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
}
spring_verts_ordered_set(spring, tspring2->ij, index2);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->type = CLOTH_SPRING_TYPE_BENDING;
spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index d35762a6f13..8cac856b560 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -224,7 +224,7 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
float w1, w2, w3, u1, u2, u3;
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
cloth1 = clmd->clothObject;
@@ -396,7 +396,7 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
#endif
double distance = 0;
float epsilon1 = clmd->coll_parms->epsilon;
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
tri_a = &clmd->clothObject->tri[overlap->indexA];
tri_b = &collmd->tri[overlap->indexB];
@@ -909,7 +909,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
// float w1, w2;
float u1, u2, u3;
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
for ( ; collpair != collision_end; collpair++ ) {
float margin_distance = (float)(collpair->distance - (double)epsilon2);
@@ -1249,7 +1249,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
/* search for overlapping collision pairs */
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+ epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
// go to next object if no overlap is there
if (result && overlap) {
@@ -1375,7 +1375,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
/* search for overlapping collision pairs */
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+ epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
// go to next object if no overlap is there
if (result && overlap) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index dabe606fa55..a591d536b43 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -535,10 +535,10 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
-static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail)
+static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
{
/* Case OBJECT */
- if (!strlen(substring)) {
+ if (substring[0] == '\0') {
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
}
@@ -573,6 +573,58 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
+ else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ /* use point along bbone */
+ Mat4 bbone[MAX_BBONE_SUBDIV];
+ float tempmat[4][4];
+ float loc[3], fac;
+
+ /* get bbone segments */
+ b_bone_spline_setup(pchan, 0, bbone);
+
+ /* figure out which segment(s) the headtail value falls in */
+ fac = (float)pchan->bone->segments * headtail;
+
+ if (fac >= pchan->bone->segments - 1) {
+ /* special case: end segment doesn't get created properly... */
+ float pt[3], sfac;
+ int index;
+
+ /* bbone points are in bonespace, so need to move to posespace first */
+ index = pchan->bone->segments - 1;
+ mul_v3_m4v3(pt, pchan->pose_mat, bbone[index].mat[3]);
+
+ /* interpolate between last segment point and the endpoint */
+ sfac = fac - (float)(pchan->bone->segments - 1); /* fac is just the "leftover" between penultimate and last points */
+ interp_v3_v3v3(loc, pt, pchan->pose_tail, sfac);
+ }
+ else {
+ /* get indices for finding interpolating between points along the bbone */
+ float pt_a[3], pt_b[3], pt[3];
+ int index_a, index_b;
+
+ index_a = floorf(fac);
+ CLAMP(index_a, 0, MAX_BBONE_SUBDIV - 1);
+
+ index_b = ceilf(fac);
+ CLAMP(index_b, 0, MAX_BBONE_SUBDIV - 1);
+
+ /* interpolate between these points */
+ copy_v3_v3(pt_a, bbone[index_a].mat[3]);
+ copy_v3_v3(pt_b, bbone[index_b].mat[3]);
+
+ interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac));
+
+ /* move the point from bone local space to pose space... */
+ mul_v3_m4v3(loc, pchan->pose_mat, pt);
+ }
+
+ /* use interpolated distance for subtarget */
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ copy_v3_v3(tempmat[3], loc);
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
else {
float tempmat[4][4], loc[3];
@@ -634,7 +686,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct)
unit_m4(ct->matrix);
}
@@ -1102,7 +1154,7 @@ static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstrai
bKinematicConstraint *data = con->data;
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct) {
if (data->flag & CONSTRAINT_IK_AUTO) {
Object *ob = cob->ob;
@@ -1985,7 +2037,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
*/
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* only execute target calculation if allowed */
#ifdef WITH_PYTHON
@@ -2097,7 +2149,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
unit_m4(ct->matrix);
/* get the transform matrix of the target */
- constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* determine where in transform range target is */
/* data->type is mapped as follows for backwards compatibility:
@@ -2143,29 +2195,26 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
}
else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
Object workob;
- bPose *pose;
+ bPose pose = {0};
bPoseChannel *pchan, *tchan;
-
- /* make a temporary pose and evaluate using that */
- pose = MEM_callocN(sizeof(bPose), "pose");
-
+
/* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
* - we need to manually copy over a few settings, including rotation order, otherwise this fails
*/
pchan = cob->pchan;
- tchan = BKE_pose_channel_verify(pose, pchan->name);
+ tchan = BKE_pose_channel_verify(&pose, pchan->name);
tchan->rotmode = pchan->rotmode;
/* evaluate action using workob (it will only set the PoseChannel in question) */
- what_does_obaction(cob->ob, &workob, pose, data->act, pchan->name, t);
+ what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t);
/* convert animation to matrices for use here */
BKE_pchan_calc_mat(tchan);
copy_m4_m4(ct->matrix, tchan->chan_mat);
/* Clean up */
- BKE_pose_free(pose);
+ BKE_pose_free_data(&pose);
}
else {
/* behavior undefined... */
@@ -3523,8 +3572,6 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
free_bvhtree_from_mesh(&treeData);
- target->release(target);
-
if (fail == true) {
/* Don't move the point */
zero_v3(co);
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 4c099987404..8afb451f768 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1402,14 +1402,14 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
}
}
- coord_fp = (float *)(((char *)coord_fp) + stride);
+ coord_fp = POINTER_OFFSET(coord_fp, stride);
if (tilt_fp)
- tilt_fp = (float *)(((char *)tilt_fp) + stride);
+ tilt_fp = POINTER_OFFSET(tilt_fp, stride);
if (radius_fp)
- radius_fp = (float *)(((char *)radius_fp) + stride);
+ radius_fp = POINTER_OFFSET(radius_fp, stride);
if (weight_fp)
- weight_fp = (float *)(((char *)weight_fp) + stride);
+ weight_fp = POINTER_OFFSET(weight_fp, stride);
u += ustep;
}
@@ -1440,7 +1440,7 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
for (a = 0; a <= it; a++) {
*p = q0;
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
q2 += q3;
@@ -1465,7 +1465,7 @@ void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q
for (a = 0; a <= it; a++) {
*p = q0;
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
}
@@ -1490,7 +1490,7 @@ static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3],
( 6.0f * t) * p3[i];
}
normalize_v3(p);
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
}
}
@@ -2102,7 +2102,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
*tilt_array = t[0] * pprev->alfa + t[1] * prevbezt->alfa + t[2] * bezt->alfa + t[3] * next->alfa;
}
- tilt_array = (float *)(((char *)tilt_array) + stride);
+ tilt_array = POINTER_OFFSET(tilt_array, stride);
}
if (radius_array) {
@@ -2123,7 +2123,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
t[2] * bezt->radius + t[3] * next->radius;
}
- radius_array = (float *)(((char *)radius_array) + stride);
+ radius_array = POINTER_OFFSET(radius_array, stride);
}
if (weight_array) {
@@ -2131,7 +2131,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
*weight_array = prevbezt->weight +
(bezt->weight - prevbezt->weight) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
- weight_array = (float *)(((char *)weight_array) + stride);
+ weight_array = POINTER_OFFSET(weight_array, stride);
}
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index a12d5434b30..de79a30bd60 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1259,7 +1259,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, NULL, NULL, NULL, layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
- {sizeof(float) * 4 * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float) * 4 * 4, "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
/* 19: CD_MDISPS */
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
layerFree_mdisps, NULL, layerSwap_mdisps, NULL,
@@ -1530,13 +1530,11 @@ void CustomData_realloc(CustomData *data, int totelem)
for (i = 0; i < data->totlayer; ++i) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
- int size;
if (layer->flag & CD_FLAG_NOFREE) {
continue;
}
typeInfo = layerType_getInfo(layer->type);
- size = totelem * typeInfo->size;
- layer->data = MEM_reallocN(layer->data, size);
+ layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -1844,7 +1842,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- const int size = totelem * typeInfo->size;
+ const size_t size = (size_t)totelem * typeInfo->size;
int flag = 0, index = data->totlayer;
void *newlayerdata = NULL;
@@ -2064,7 +2062,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->copy) {
- void *dst_data = MEM_mallocN(totelem * typeInfo->size, "CD duplicate ref layer");
+ void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer");
typeInfo->copy(layer->data, dst_data, totelem);
layer->data = dst_data;
}
@@ -2172,7 +2170,7 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs,
if (typeInfo->copy)
typeInfo->copy(src_data_ofs, dst_data_ofs, count);
else
- memcpy(dst_data_ofs, src_data_ofs, count * typeInfo->size);
+ memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
}
static void CustomData_copy_data_layer(
@@ -2181,16 +2179,14 @@ static void CustomData_copy_data_layer(
int src_index, int dst_index, int count)
{
const LayerTypeInfo *typeInfo;
- int src_offset;
- int dst_offset;
const void *src_data = source->layers[src_i].data;
void *dst_data = dest->layers[dst_i].data;
typeInfo = layerType_getInfo(source->layers[src_i].type);
- src_offset = src_index * typeInfo->size;
- dst_offset = dst_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+ const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
if (count && !(src_data == NULL && dst_data == NULL)) {
@@ -2201,14 +2197,16 @@ static void CustomData_copy_data_layer(
return;
}
- if (typeInfo->copy)
+ if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset),
POINTER_OFFSET(dst_data, dst_offset),
count);
- else
+ }
+ else {
memcpy(POINTER_OFFSET(dst_data, dst_offset),
POINTER_OFFSET(src_data, src_offset),
- count * typeInfo->size);
+ (size_t)count * typeInfo->size);
+ }
}
void CustomData_copy_data_named(const CustomData *source, CustomData *dest,
@@ -2270,7 +2268,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = index * typeInfo->size;
+ size_t offset = (size_t)index * typeInfo->size;
typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
}
@@ -2281,7 +2279,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
void CustomData_interp(const CustomData *source, CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index)
{
int src_i, dest_i;
@@ -2316,11 +2314,11 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
void *src_data = source->layers[src_i].data;
for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_data, src_indices[j] * typeInfo->size);
+ sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
typeInfo->interp(sources, weights, sub_weights, count,
- POINTER_OFFSET(dest->layers[dest_i].data, dest_index * typeInfo->size));
+ POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
@@ -2349,7 +2347,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
- const int offset = index * typeInfo->size;
+ const size_t offset = (size_t)index * typeInfo->size;
typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
}
@@ -2387,7 +2385,6 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
void *CustomData_get(const CustomData *data, int index, int type)
{
- int offset;
int layer_index;
BLI_assert(index >= 0);
@@ -2397,7 +2394,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
if (layer_index == -1) return NULL;
/* get the offset of the desired element */
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index].data, offset);
}
@@ -2405,7 +2402,6 @@ void *CustomData_get(const CustomData *data, int index, int type)
void *CustomData_get_n(const CustomData *data, int type, int index, int n)
{
int layer_index;
- int offset;
BLI_assert(index >= 0 && n >= 0);
@@ -2413,7 +2409,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
layer_index = data->typemap[type];
if (layer_index == -1) return NULL;
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
}
@@ -2838,7 +2834,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = data->layers[i].offset;
+ const size_t offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
}
}
@@ -3218,7 +3214,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
int src_index, void **dest_block, bool use_default_init)
{
const LayerTypeInfo *typeInfo;
- int dest_i, src_i, src_offset;
+ int dest_i, src_i;
if (*dest_block == NULL)
CustomData_bmesh_alloc_block(dest, dest_block);
@@ -3247,7 +3243,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
void *dest_data = POINTER_OFFSET(*dest_block, offset);
typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- src_offset = src_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
if (typeInfo->copy)
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
@@ -3294,7 +3290,7 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
- void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, dst_index * typeInfo->size);
+ void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dst_index * typeInfo->size);
if (typeInfo->copy)
typeInfo->copy(src_data, dst_data, 1);
@@ -3311,12 +3307,12 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
}
-void CustomData_file_write_info(int type, const char **structname, int *structnum)
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- *structname = typeInfo->structname;
- *structnum = typeInfo->structnum;
+ *r_struct_name = typeInfo->structname;
+ *r_struct_num = typeInfo->structnum;
}
/**
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 1dcacc3ae0a..7292ed2b5c5 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -459,9 +459,18 @@ static void data_transfer_layersmapping_add_item_cd(
ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
void *data_src, void *data_dst, cd_datatransfer_interp interp, void *interp_data)
{
+ uint64_t data_flag = 0;
+
+ if (cddata_type == CD_FREESTYLE_EDGE) {
+ data_flag = FREESTYLE_EDGE_MARK;
+ }
+ else if (cddata_type == CD_FREESTYLE_FACE) {
+ data_flag = FREESTYLE_FACE_MARK;
+ }
+
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst,
- 0, 0, 0, 0, 0, 0, interp, interp_data);
+ 0, 0, 0, 0, 0, data_flag, interp, interp_data);
}
/* Note: All those layer mapping handlers return false *only* if they were given invalid parameters.
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index a029c8c7748..14c230e4a45 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -937,6 +937,8 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
}
dag->need_update = false;
+ BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false);
+
/* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */
BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
@@ -948,14 +950,43 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
/* add current scene objects */
for (base = sce->base.first; base; base = base->next) {
ob = base->object;
-
+ ob->id.tag |= LIB_TAG_DOIT;
build_dag_object(dag, scenenode, bmain, sce, ob, mask);
if (ob->proxy)
build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask);
if (ob->dup_group)
build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
}
-
+
+ /* There might be situations when object from current scene depends on
+ * objects form other scene AND objects from other scene has own
+ * dependencies on objects from other scene.
+ *
+ * This is really important to include such indirect dependencies in order
+ * to keep threaded update safe but since we don't really know if object is
+ * coming from current scene or another scene we do rather stupid tag-based
+ * check here: all the objects for which build_dag_object() was called are
+ * getting tagged with LIB_TAG_DOIT. This way if some node has untagged
+ * object we know it's an object from other scene.
+ *
+ * It should be enough to to it once, because if there's longer chain of
+ * indirect dependencies, all the new nodes will be added to the end of the
+ * list, meaning we'll keep covering them in this for loop.
+ */
+ for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) {
+ if (node->type == ID_OB) {
+ ob = node->ob;
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ build_dag_object(dag, scenenode, bmain, sce, ob, mask);
+ if (ob->proxy)
+ build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask);
+ if (ob->dup_group)
+ build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
+ }
+ }
+ }
+
BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
/* Now all relations were built, but we need to solve 1 exceptional case;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index dbf095d3832..18672b93714 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -85,7 +85,7 @@
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
+//# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
/* precalculated gaussian factors for 5x super sampling */
@@ -123,7 +123,7 @@ static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* dissolve inline function */
-BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const int is_log)
+BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
{
*r_value = (is_log) ?
(*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
@@ -144,13 +144,12 @@ typedef struct Bounds3D {
typedef struct VolumeGrid {
int dim[3];
- Bounds3D grid_bounds; /* whole grid bounds */
+ Bounds3D grid_bounds; /* whole grid bounds */
- Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
- int *s_pos; /* (x*y*z) t_index begin id */
- int *s_num; /* (x*y*z) number of t_index points */
- int *t_index; /* actual surface point index,
- * access: (s_pos+s_num) */
+ Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
+ int *s_pos; /* (x*y*z) t_index begin id */
+ int *s_num; /* (x*y*z) number of t_index points */
+ int *t_index; /* actual surface point index, access: (s_pos + s_num) */
} VolumeGrid;
typedef struct Vec3f {
@@ -165,21 +164,20 @@ typedef struct BakeAdjPoint {
/* Surface data used while processing a frame */
typedef struct PaintBakeNormal {
float invNorm[3]; /* current pixel world-space inverted normal */
- float normal_scale; /* normal directional scale for displace mapping */
+ float normal_scale; /* normal directional scale for displace mapping */
} PaintBakeNormal;
/* Temp surface data used to process a frame */
typedef struct PaintBakeData {
/* point space data */
PaintBakeNormal *bNormal;
- int *s_pos; /* index to start reading point sample realCoord */
- int *s_num; /* num of realCoord samples */
- Vec3f *realCoord; /* current pixel center world-space coordinates for each sample
- * ordered as (s_pos+s_num)*/
+ int *s_pos; /* index to start reading point sample realCoord */
+ int *s_num; /* num of realCoord samples */
+ Vec3f *realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
Bounds3D mesh_bounds;
/* adjacency info */
- BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
+ BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
double average_dist;
/* space partitioning */
VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
@@ -188,7 +186,7 @@ typedef struct PaintBakeData {
Vec3f *velocity; /* speed vector in global space movement per frame, if required */
Vec3f *prev_velocity;
float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
- * 3 float dir vec + 1 float str */
+ * 3 float dir vec + 1 float str */
MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
float prev_obmat[4][4]; /* previous frame object matrix */
int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
@@ -201,8 +199,7 @@ typedef struct PaintUVPoint {
unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
unsigned int v1, v2, v3; /* vertex indexes */
- unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
- * but it's neighboring pixel is */
+ unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
} PaintUVPoint;
typedef struct ImgSeqFormatData {
@@ -214,8 +211,7 @@ typedef struct ImgSeqFormatData {
#define ADJ_ON_MESH_EDGE (1 << 0)
typedef struct PaintAdjData {
- int *n_target; /* array of neighboring point indexes,
- * for single sample use (n_index + neigh_num) */
+ int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
int *n_index; /* index to start reading n_target for each point */
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
@@ -239,11 +235,10 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0; /* not supported atm */
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (!surface->canvas->dm) return 0; /* invalid derived mesh */
- return surface->canvas->dm->getNumVerts(surface->canvas->dm);
+ return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0;
}
- else
- return 0;
+
+ return 0;
}
/* checks whether surface's format/type has realtime preview */
@@ -253,32 +248,16 @@ bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
return false;
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- return false;
- }
- else {
- return true;
- }
- }
- else {
- return true;
+ return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
}
+
+ return true;
}
/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
- DynamicPaintSurface *surface = canvas->surfaces.first;
- int i;
-
- for (i = 0; surface; surface = surface->next) {
- if (i == canvas->active_sur)
- return surface;
- i++;
- }
- return NULL;
+ return BLI_findlink(&canvas->surfaces, canvas->active_sur);
}
/* set preview to first previewable surface */
@@ -292,8 +271,9 @@ void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
surface->flags |= MOD_DPAINT_PREVIEW;
done = true;
}
- else
+ else {
surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
}
@@ -325,8 +305,9 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
Mesh *me = ob->data;
return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
- return (defgroup_name_index(ob, surface->output_name) != -1);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ return (defgroup_name_index(ob, name) != -1);
+ }
}
return false;
@@ -334,15 +315,16 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
static bool surface_duplicateOutputExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && surface->type == t_surface->type &&
- surface->format == t_surface->format)
- {
- if (surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) return true;
- if (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)) return true;
+ if (surface != t_surface && surface->type == t_surface->type && surface->format == t_surface->format) {
+ if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
+ (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
+ {
+ return true;
+ }
}
}
return false;
@@ -352,20 +334,25 @@ static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *base
{
char name[64];
BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- if (!output)
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name, sizeof(surface->output_name));
- if (output)
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name2, sizeof(surface->output_name2));
+ if (output == 0) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name, sizeof(surface->output_name));
+ }
+ else if (output == 1) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name2, sizeof(surface->output_name2));
+ }
}
static bool surface_duplicateNameExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && STREQ(name, surface->name)) return true;
+ if (surface != t_surface && STREQ(name, surface->name))
+ return true;
}
return false;
}
@@ -420,9 +407,7 @@ void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
static int surface_totalSamples(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
return (surface->data->total_points * 5);
}
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
@@ -436,6 +421,7 @@ static int surface_totalSamples(DynamicPaintSurface *surface)
static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
{
+ /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
int i;
float i_alpha = 1.0f - s_alpha;
float f_alpha = t_alpha * i_alpha + s_alpha;
@@ -508,15 +494,11 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
- else
+ else {
brushObj = base->object;
-
- if (!brushObj) {
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
}
if (surface->brush_group)
@@ -524,6 +506,10 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
else
base = base->next;
+ if (!brushObj) {
+ continue;
+ }
+
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -546,50 +532,52 @@ static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
}
/* check whether two bounds intersect */
-static int boundsIntersect(Bounds3D *b1, Bounds3D *b2)
+static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
+ return false;
+ }
+ return true;
}
/* check whether two bounds intersect inside defined proximity */
-static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist)
+static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
+ return false;
+ }
+ return true;
}
/* check whether bounds intersects a point with given radius */
-static int boundIntersectPoint(Bounds3D *b, float point[3], float radius)
+static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
{
- int i = 2;
- if (!b->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) return 0;
- return 1;
+ if (!b->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
+ return false;
+ }
+ return true;
}
/* expand bounds by a new point */
static void boundInsert(Bounds3D *b, float point[3])
{
- int i = 2;
if (!b->valid) {
copy_v3_v3(b->min, point);
copy_v3_v3(b->max, point);
b->valid = 1;
+ return;
}
- else {
- for (; i >= 0; i -= 1) {
- if (point[i] < b->min[i]) b->min[i] = point[i];
- if (point[i] > b->max[i]) b->max[i] = point[i];
- }
- }
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
@@ -636,7 +624,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
grid = bData->grid;
- if (grid && grid_bounds) {
+ {
int i, error = 0;
float dim_factor, volume, dim[3];
float td[3];
@@ -659,6 +647,8 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
boundInsert(&grid->grid_bounds, grid_bounds[i].max);
}
+ MEM_freeN(grid_bounds);
+
/* get dimensions */
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
copy_v3_v3(td, dim);
@@ -666,11 +656,13 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* deactivate zero axises */
for (i = 0; i < 3; i++) {
- if (td[i] < min_dim) { td[i] = 1.0f; axis -= 1; }
+ if (td[i] < min_dim) {
+ td[i] = 1.0f;
+ axis--;
+ }
}
if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
- MEM_freeN(grid_bounds);
MEM_freeN(bData->grid);
bData->grid = NULL;
return;
@@ -764,8 +756,10 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
}
- if (temp_s_num) MEM_freeN(temp_s_num);
- if (temp_t_index) MEM_freeN(temp_t_index);
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
/* free per thread s_num values */
grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
@@ -775,8 +769,6 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
freeGrid(sData);
}
}
-
- if (grid_bounds) MEM_freeN(grid_bounds);
}
/***************************** Freeing data ******************************/
@@ -791,10 +783,8 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
if (pmd->brush->paint_ramp)
MEM_freeN(pmd->brush->paint_ramp);
- pmd->brush->paint_ramp = NULL;
if (pmd->brush->vel_ramp)
MEM_freeN(pmd->brush->vel_ramp);
- pmd->brush->vel_ramp = NULL;
MEM_freeN(pmd->brush);
pmd->brush = NULL;
@@ -804,10 +794,14 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
{
if (data->adj_data) {
- if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
- if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num);
- if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
- if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->n_index)
+ MEM_freeN(data->adj_data->n_index);
+ if (data->adj_data->n_num)
+ MEM_freeN(data->adj_data->n_num);
+ if (data->adj_data->n_target)
+ MEM_freeN(data->adj_data->n_target);
+ if (data->adj_data->flags)
+ MEM_freeN(data->adj_data->flags);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -817,15 +811,24 @@ static void free_bakeData(PaintSurfaceData *data)
{
PaintBakeData *bData = data->bData;
if (bData) {
- if (bData->bNormal) MEM_freeN(bData->bNormal);
- if (bData->s_pos) MEM_freeN(bData->s_pos);
- if (bData->s_num) MEM_freeN(bData->s_num);
- if (bData->realCoord) MEM_freeN(bData->realCoord);
- if (bData->bNeighs) MEM_freeN(bData->bNeighs);
- if (bData->grid) freeGrid(data);
- if (bData->prev_verts) MEM_freeN(bData->prev_verts);
- if (bData->velocity) MEM_freeN(bData->velocity);
- if (bData->prev_velocity) MEM_freeN(bData->prev_velocity);
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ if (bData->grid)
+ freeGrid(data);
+ if (bData->prev_verts)
+ MEM_freeN(bData->prev_verts);
+ if (bData->velocity)
+ MEM_freeN(bData->velocity);
+ if (bData->prev_velocity)
+ MEM_freeN(bData->prev_velocity);
MEM_freeN(data->bData);
data->bData = NULL;
@@ -835,12 +838,11 @@ static void free_bakeData(PaintSurfaceData *data)
/* free surface data if it's not used anymore */
static void surface_freeUnusedData(DynamicPaintSurface *surface)
{
- if (!surface->data) return;
+ if (!surface->data)
+ return;
/* free bakedata if not active or surface is baked */
- if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
- (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED))
- {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE) || (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
free_bakeData(surface->data);
}
}
@@ -848,7 +850,9 @@ static void surface_freeUnusedData(DynamicPaintSurface *surface)
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
PaintSurfaceData *data = surface->data;
- if (!data) return;
+ if (!data)
+ return;
+
if (data->format_data) {
/* format specific free */
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -861,7 +865,8 @@ void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
MEM_freeN(data->format_data);
}
/* type data */
- if (data->type_data) MEM_freeN(data->type_data);
+ if (data->type_data)
+ MEM_freeN(data->type_data);
dynamicPaint_freeAdjData(data);
/* bake data */
free_bakeData(data);
@@ -1224,31 +1229,24 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
break;
}
- if (sData->type_data == NULL) setError(surface->canvas, N_("Not enough free memory"));
+ if (sData->type_data == NULL)
+ setError(surface->canvas, N_("Not enough free memory"));
}
-static int surface_usesAdjDistance(DynamicPaintSurface *surface)
+static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
{
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1;
- if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1;
- return 0;
+ return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
}
-static int surface_usesAdjData(DynamicPaintSurface *surface)
+static bool surface_usesAdjData(DynamicPaintSurface *surface)
{
- if (surface_usesAdjDistance(surface)) return 1;
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
- return 1;
- }
- else {
- return 0;
- }
+ return (surface_usesAdjDistance(surface) ||
+ (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS));
}
/* initialize surface adjacency data */
-static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
+static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
DerivedMesh *dm = surface->canvas->dm;
@@ -1256,20 +1254,24 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int *temp_data;
int neigh_points = 0;
- if (!surface_usesAdjData(surface) && !force_init) return;
+ if (!surface_usesAdjData(surface) && !force_init)
+ return;
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbors are connected by edges */
neigh_points = 2 * dm->getNumEdges(dm);
}
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
neigh_points = sData->total_points * 8;
+ }
- if (!neigh_points) return;
+ if (!neigh_points)
+ return;
/* allocate memory */
ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
- if (!ad) return;
+ if (!ad)
+ return;
ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
@@ -1280,7 +1282,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
dynamicPaint_freeAdjData(sData);
- if (temp_data) MEM_freeN(temp_data);
+ if (temp_data)
+ MEM_freeN(temp_data);
setError(surface->canvas, N_("Not enough free memory"));
return;
}
@@ -1308,8 +1311,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* also add number of vertices to temp_data
* to locate points on "mesh edge" */
for (i = 0; i < numOfPolys; i++) {
- int j = 0;
- for (; j < mpoly[i].totloop; j++) {
+ for (int j = 0; j < mpoly[i].totloop; j++) {
temp_data[mloop[mpoly[i].loopstart + j].v]++;
}
}
@@ -1317,9 +1319,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* now check if total number of edges+faces for
* each vertex is even, if not -> vertex is on mesh edge */
for (i = 0; i < sData->total_points; i++) {
- if ((temp_data[i] % 2) ||
- (temp_data[i] < 4))
- {
+ if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
ad->flags[i] |= ADJ_ON_MESH_EDGE;
}
@@ -1370,8 +1370,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
return;
+
/* Single color */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
/* apply color to every surface point */
#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
@@ -1389,12 +1390,14 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- if (!tex) return;
+ if (!tex)
+ return;
/* get uv map */
CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname);
mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
- if (!mloopuv) return;
+ if (!mloopuv)
+ return;
/* for vertex surface loop through tfaces and find uv color
* that provides highest alpha */
@@ -1462,7 +1465,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
const MLoop *mloop = dm->getLoopArray(dm);
const int totloop = dm->getNumLoops(dm);
const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
+ if (!col)
+ return;
#pragma omp parallel for schedule(static)
for (i = 0; i < totloop; i++) {
@@ -1474,7 +1478,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
+ if (!col)
+ return;
#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
@@ -1527,20 +1532,24 @@ bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
/* free existing data */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
/* don't reallocate for image sequence types. they get handled only on bake */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return true;
- if (numOfPoints < 1) return false;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return true;
+ if (numOfPoints < 1)
+ return false;
/* allocate memory */
surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data) return false;
+ if (!surface->data)
+ return false;
/* allocate data depending on surface type and format */
surface->data->total_points = numOfPoints;
dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_initAdjacencyData(surface, 0);
+ dynamicPaint_initAdjacencyData(surface, false);
/* set initial color */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
@@ -1567,7 +1576,8 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
{
PaintSurfaceData *sData = surface->data;
- if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return;
+ if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
+ return;
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -1591,9 +1601,8 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
/*
* Apply canvas data to the object derived mesh
*/
-static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
- Object *ob,
- DerivedMesh *dm)
+static DerivedMesh *dynamicPaint_Modifier_apply(
+ DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result = CDDM_copy(dm);
@@ -1607,7 +1616,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
PaintSurfaceData *sData = surface->data;
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
- if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue;
+ if (!(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
/* process vertex surface previews */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
@@ -1627,7 +1637,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
/* blend dry and wet layer */
- blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], &fcolor[i * 4]);
+ blendColors(pPoint[i].color, pPoint[i].color[3],
+ pPoint[i].e_color, pPoint[i].e_color[3], &fcolor[i * 4]);
}
/* viewport preview */
@@ -1647,17 +1658,17 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* Save preview results to weight layer to be
* able to share same drawing methods */
col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
- if (!col)
- col = CustomData_add_layer(&result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC,
- NULL, totloop);
+ if (!col) {
+ col = CustomData_add_layer(
+ &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ }
if (col) {
#pragma omp parallel for schedule(static)
for (i = 0; i < totpoly; i++) {
- int j = 0;
Material *material = give_current_material(ob, mp[i].mat_nr + 1);
- for (; j < mp[i].totloop; j++) {
+ for (int j = 0; j < mp[i].totloop; j++) {
int l_index = mp[i].loopstart + j;
int v_index = mloop[l_index].v;
@@ -1683,9 +1694,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
rgb_float_to_uchar((unsigned char *)&col[l_index].r, c);
}
else {
- col[l_index].r =
- col[l_index].g =
- col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ col[l_index].r = c;
+ col[l_index].g = c;
+ col[l_index].b = c;
col[l_index].a = 255;
}
}
@@ -1699,15 +1711,16 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* paint layer */
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ if (!col && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ col = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ }
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
for (i = 0; i < totloop; i++) {
int index = mloop[i].v * 4;
- rgb_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
- col[i].a = FTOCHAR(fcolor[index + 3]); /* IS THIS NEEDED? */
+ rgba_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
}
}
@@ -1716,16 +1729,18 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* wet layer */
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ if (!col && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ col = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
for (i = 0; i < totloop; i++) {
- int index = mloop[i].v;
- col[i].r =
- col[i].g =
- col[i].b = FTOCHAR(pPoint[index].wetness);
+ const char c = FTOCHAR(pPoint[mloop[i].v].wetness);
+ col[i].r = c;
+ col[i].g = c;
+ col[i].b = c;
col[i].a = 255;
}
}
@@ -1748,9 +1763,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* apply weights into a vertex group, if doesnt exists add a new layer */
- if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0'))
+ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
NULL, sData->total_points, surface->output_name);
+ }
if (defgrp_index != -1 && dvert) {
int i;
for (i = 0; i < sData->total_points; i++) {
@@ -1759,7 +1775,6 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* skip if weight value is 0 and no existing weight is found */
if ((def_weight != NULL) || (weight[i] != 0.0f)) {
-
/* if not found, add a weight for it */
if (def_weight == NULL) {
def_weight = defvert_verify_index(dv, defgrp_index);
@@ -1801,7 +1816,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* make a copy of dm to use as brush data */
if (pmd->brush) {
- if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
+ if (pmd->brush->dm)
+ pmd->brush->dm->release(pmd->brush->dm);
pmd->brush->dm = CDDM_copy(result);
}
@@ -1839,7 +1855,8 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
canvas_copyDerivedMesh(canvas, dm);
/* in case image sequence baking, stop here */
- if (canvas->flags & MOD_DPAINT_BAKING) return;
+ if (canvas->flags & MOD_DPAINT_BAKING)
+ return;
/* loop through surfaces */
for (; surface; surface = surface->next) {
@@ -1850,17 +1867,20 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
surface_freeUnusedData(surface);
/* image sequences are handled by bake operator */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue;
- if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue;
+ if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) || !(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
/* make sure surface is valid */
no_surface_data = surface->data == NULL;
- if (!dynamicPaint_checkSurfaceData(scene, surface)) continue;
+ if (!dynamicPaint_checkSurfaceData(scene, surface))
+ continue;
/* limit frame range */
CLAMP(current_frame, surface->start_frame, surface->end_frame);
- if (no_surface_data || current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
+ if (no_surface_data || current_frame != surface->current_frame ||
+ (int)scene->r.cfra == surface->start_frame)
+ {
PointCache *cache = surface->pointcache;
PTCacheID pid;
surface->current_frame = current_frame;
@@ -1943,8 +1963,8 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
x = px + neighX[n_index];
y = py + neighY[n_index];
- if (x < 0 || x >= w) return OUT_OF_TEXTURE;
- if (y < 0 || y >= h) return OUT_OF_TEXTURE;
+ if (x < 0 || x >= w || y < 0 || y >= h)
+ return OUT_OF_TEXTURE;
tPoint = &tempPoints[x + w * y]; /* UV neighbor */
cPoint = &tempPoints[px + w * py]; /* Origin point */
@@ -1993,8 +2013,8 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
/* distances only used for comparison */
float dist_squared, t_dist_squared;
- int i, edge1_index, edge2_index,
- e1_index, e2_index, target_tri;
+ int i, edge1_index, edge2_index;
+ int e1_index, e2_index, target_tri;
float closest_point[2], lambda, dir_vec[2];
int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
@@ -2050,33 +2070,28 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
target_tri = -1;
for (i = 0; i < tottri; i++) {
+ const int v0 = mloop[mlooptri[i].tri[0]].v;
+ const int v1 = mloop[mlooptri[i].tri[1]].v;
+ const int v2 = mloop[mlooptri[i].tri[2]].v;
/*
* Check if both edge vertices share this face
*/
- if ((e1_index == mloop[mlooptri[i].tri[0]].v || e1_index == mloop[mlooptri[i].tri[1]].v || e1_index == mloop[mlooptri[i].tri[2]].v) &&
- (e2_index == mloop[mlooptri[i].tri[0]].v || e2_index == mloop[mlooptri[i].tri[1]].v || e2_index == mloop[mlooptri[i].tri[2]].v))
- {
- if (i == cPoint->tri_index) continue;
+ if (ELEM(e1_index, v0, v1, v2) && ELEM(e2_index, v0, v1, v2)) {
+ if (i == cPoint->tri_index)
+ continue;
target_tri = i;
- /*
- * Get edge UV index
- */
- if (e1_index == mloop[mlooptri[i].tri[0]].v) target_uv1 = 0;
- else if (e1_index == mloop[mlooptri[i].tri[1]].v) target_uv1 = 1;
- else if (e1_index == mloop[mlooptri[i].tri[2]].v) target_uv1 = 2;
-
- if (e2_index == mloop[mlooptri[i].tri[0]].v) target_uv2 = 0;
- else if (e2_index == mloop[mlooptri[i].tri[1]].v) target_uv2 = 1;
- else if (e2_index == mloop[mlooptri[i].tri[2]].v) target_uv2 = 2;
-
+ /* Get edge UV index */
+ target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
+ target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
break;
}
}
/* If none found pixel is on mesh edge */
- if (target_tri == -1) return ON_MESH_EDGE;
+ if (target_tri == -1)
+ return ON_MESH_EDGE;
/*
* If target face is connected in UV space as well, just use original index
@@ -2104,8 +2119,7 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
closest_point, pixel,
mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- if (lambda < 0.0f) lambda = 0.0f;
- if (lambda > 1.0f) lambda = 1.0f;
+ CLAMP(lambda, 0.0f, 1.0f);
sub_v2_v2v2(
dir_vec,
@@ -2119,26 +2133,25 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
pixel[0] = (pixel[0] * (float)w) - 0.5f;
pixel[1] = (pixel[1] * (float)h) - 0.5f;
- final_pixel[0] = (int)floor(pixel[0]);
- final_pixel[1] = (int)floor(pixel[1]);
+ final_pixel[0] = (int)floorf(pixel[0]);
+ final_pixel[1] = (int)floorf(pixel[1]);
/* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w) return OUT_OF_TEXTURE;
- if (final_pixel[1] < 0 || final_pixel[1] >= h) return OUT_OF_TEXTURE;
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
+ return OUT_OF_TEXTURE;
final_index = final_pixel[0] + w * final_pixel[1];
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px + w * py)) return NOT_FOUND;
+ if (final_index == (px + w * py))
+ return NOT_FOUND;
/* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
+ if (tempPoints[final_index].tri_index != target_tri)
return NOT_FOUND;
- }
- /*
- * If final point is an "edge pixel", use it's "real" neighbor instead
- */
- if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1)
+ final_index = cPoint->neighbour_pixel;
return final_index;
}
@@ -2163,7 +2176,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
int tottri;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
int active_points = 0;
- int error = 0;
+ bool error = false;
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
@@ -2208,20 +2221,24 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i tris.\n", w, h, tottri);
/* Init data struct */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
if (!surface->data)
return setError(canvas, N_("Not enough free memory"));
aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
- if (!tempPoints) error = 1;
+ if (!tempPoints)
+ error = true;
final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
- if (!final_index) error = 1;
+ if (!final_index)
+ error = true;
tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
- if (!tempWeights) error = 1;
+ if (!tempWeights)
+ error = true;
/*
* Generate a temporary bounding box array for UV faces to optimize
@@ -2229,10 +2246,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
*/
if (!error) {
faceBB = (struct Bounds2D *) MEM_mallocN(tottri * sizeof(struct Bounds2D), "MPCanvasFaceBB");
- if (!faceBB) error = 1;
+ if (!faceBB)
+ error = true;
}
- if (!error)
+ if (!error) {
for (ty = 0; ty < tottri; ty++) {
int i;
@@ -2240,18 +2258,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
copy_v2_v2(faceBB[ty].max, mloopuv[mlooptri[ty].tri[0]].uv);
for (i = 1; i < 3; i++) {
- CLAMP_MAX(faceBB[ty].min[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MAX(faceBB[ty].min[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
- CLAMP_MIN(faceBB[ty].max[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MIN(faceBB[ty].max[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
+ minmax_v2v2_v2(faceBB[ty].min, faceBB[ty].max, mloopuv[mlooptri[ty].tri[i]].uv);
}
}
- /*
- * Loop through every pixel and check
- * if pixel is uv-mapped on a canvas face.
- */
- if (!error) {
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
#pragma omp parallel for schedule(static)
for (ty = 0; ty < h; ty++) {
int tx;
@@ -2259,11 +2270,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
int i, sample;
int index = tx + w * ty;
PaintUVPoint *tPoint = (&tempPoints[index]);
-
- bool isInside = false; /* if point is inside a uv face */
-
- float d1[2], d2[2], d3[2], point[5][2];
- float dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
+ float point[5][2];
/* Init per pixel settings */
tPoint->tri_index = -1;
@@ -2293,54 +2300,31 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* Loop through samples, starting from middle point */
for (sample = 0; sample < 5; sample++) {
-
/* Loop through every face in the mesh */
for (i = 0; i < tottri; i++) {
-
/* Check uv bb */
- if (faceBB[i].min[0] > (point[sample][0])) continue;
- if (faceBB[i].min[1] > (point[sample][1])) continue;
- if (faceBB[i].max[0] < (point[sample][0])) continue;
- if (faceBB[i].max[1] < (point[sample][1])) continue;
-
- /* Calculate point inside a triangle check
- * for uv0, 1, 2 */
- sub_v2_v2v2(d1, mloopuv[mlooptri[i].tri[2]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv2 - uv0 */
- sub_v2_v2v2(d2, mloopuv[mlooptri[i].tri[1]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv1 - uv0 */
- sub_v2_v2v2(d3, point[sample], mloopuv[mlooptri[i].tri[0]].uv); /* point - uv0 */
-
- dot00 = d1[0] * d1[0] + d1[1] * d1[1];
- dot01 = d1[0] * d2[0] + d1[1] * d2[1];
- dot02 = d1[0] * d3[0] + d1[1] * d3[1];
- dot11 = d2[0] * d2[0] + d2[1] * d2[1];
- dot12 = d2[0] * d3[0] + d2[1] * d3[1];
-
- invDenom = (dot00 * dot11 - dot01 * dot01);
- invDenom = invDenom ? 1.0f / invDenom : 1.0f;
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-
- if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = true; } /* is inside a triangle */
-
- /*
- * If point was inside the face
- */
- if (isInside) {
+ if ((faceBB[i].min[0] > (point[sample][0])) ||
+ (faceBB[i].min[1] > (point[sample][1])) ||
+ (faceBB[i].max[0] < (point[sample][0])) ||
+ (faceBB[i].max[1] < (point[sample][1])))
+ {
+ continue;
+ }
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int j;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
- /* Get triagnle uvs */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
+ /* If point is inside the face */
+ if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
+ float uv[2];
/* Add b-weights per anti-aliasing sample */
- for (j = 0; j < aa_samples; j++) {
+ for (int j = 0; j < aa_samples; j++) {
uv[0] = point[0][0] + jitter5sample[j * 2] / w;
uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
}
/* Set surface point face values */
@@ -2396,21 +2380,18 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* if neighbor has index */
if (tempPoints[ind].tri_index != -1) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int i = tempPoints[ind].tri_index, j;
+ float uv[2];
+ const int i = tempPoints[ind].tri_index;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
/* Now calculate pixel data for this pixel as it was on polygon surface */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
-
/* Add b-weights per anti-aliasing sample */
- for (j = 0; j < aa_samples; j++) {
-
+ for (int j = 0; j < aa_samples; j++) {
uv[0] = point[0] + jitter5sample[j * 2] / w;
uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
}
/* Set values */
@@ -2461,7 +2442,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* allocate memory */
sData->total_points = w * h;
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (sData->adj_data) {
PaintAdjData *ed = sData->adj_data;
@@ -2503,7 +2484,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
- if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
+ if (!f_data->uv_p || !f_data->barycentricWeights)
+ error = 1;
}
else {
error = 1;
@@ -2514,8 +2496,10 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* in case of allocation error, free everything */
if (error) {
if (f_data) {
- if (f_data->uv_p) MEM_freeN(f_data->uv_p);
- if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights);
+ if (f_data->uv_p)
+ MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights)
+ MEM_freeN(f_data->barycentricWeights);
MEM_freeN(f_data);
}
}
@@ -2527,7 +2511,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
for (index = 0; index < (w * h); index++) {
if (tempPoints[index].tri_index != -1) {
memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
- memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], sizeof(Vec3f) * aa_samples);
+ memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
+ sizeof(Vec3f) * aa_samples);
cursor++;
}
}
@@ -2537,10 +2522,14 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (error == 1)
setError(canvas, N_("Not enough free memory"));
- if (faceBB) MEM_freeN(faceBB);
- if (tempPoints) MEM_freeN(tempPoints);
- if (tempWeights) MEM_freeN(tempWeights);
- if (final_index) MEM_freeN(final_index);
+ if (faceBB)
+ MEM_freeN(faceBB);
+ if (tempPoints)
+ MEM_freeN(tempPoints);
+ if (tempWeights)
+ MEM_freeN(tempWeights);
+ if (final_index)
+ MEM_freeN(final_index);
/* Init surface type data */
if (!error) {
@@ -2551,19 +2540,21 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* For debug, output pixel statuses to the color map
* -----------------------------------------------------------------*/
#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++)
- {
+ for (index = 0; index < sData->total_points; index++) {
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
pPoint->alpha = 1.0f;
/* Every pixel that is assigned as "edge pixel" gets blue color */
- if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
+ if (uvPoint->neighbour_pixel != -1)
+ pPoint->color[2] = 1.0f;
/* and every pixel that finally got an polygon gets red color */
- if (uvPoint->tri_index != -1) pPoint->color[0] = 1.0f;
+ if (uvPoint->tri_index != -1)
+ pPoint->color[0] = 1.0f;
/* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1) pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ if (uvPoint->tri_index != -1)
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
}
#endif
@@ -2592,7 +2583,8 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
/* if selected format is openexr, but current build doesnt support one */
#ifndef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
+ if (format == R_IMF_IMTYPE_OPENEXR)
+ format = R_IMF_IMTYPE_PNG;
#endif
BLI_strncpy(output_file, filename, sizeof(output_file));
BKE_image_path_ensure_ext_from_imtype(output_file, format);
@@ -2619,9 +2611,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
- ibuf->rect_float[pos] = value;
- ibuf->rect_float[pos + 1] = value;
- ibuf->rect_float[pos + 2] = value;
+ copy_v3_fl(&ibuf->rect_float[pos], value);
ibuf->rect_float[pos + 3] = 1.0f;
}
}
@@ -2635,9 +2625,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
/* Multiply color by alpha if enabled */
if (surface->flags & MOD_DPAINT_MULALPHA) {
- ibuf->rect_float[pos] *= ibuf->rect_float[pos + 3];
- ibuf->rect_float[pos + 1] *= ibuf->rect_float[pos + 3];
- ibuf->rect_float[pos + 2] *= ibuf->rect_float[pos + 3];
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
}
}
/* displace */
@@ -2652,9 +2640,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
CLAMP(depth, 0.0f, 1.0f);
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
ibuf->rect_float[pos + 3] = 1.0f;
}
/* waves */
@@ -2666,9 +2652,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
depth = (0.5f + depth / 2.0f);
CLAMP(depth, 0.0f, 1.0f);
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
ibuf->rect_float[pos + 3] = 1.0f;
}
}
@@ -2762,9 +2746,11 @@ static void dynamicPaint_doMaterialTex(
if (mat == NULL) {
if (bMats->ob_mats) {
int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb))) return;
+ if (mat_nr >= (*give_totcolp(brushOb)))
+ return;
mat = bMats->ob_mats[mat_nr];
- if (mat == NULL) return; /* No material assigned */
+ if (mat == NULL)
+ return; /* No material assigned */
}
else {
return;
@@ -2777,7 +2763,7 @@ static void dynamicPaint_doMaterialTex(
/***************************** Ray / Nearest Point Utils ******************************/
-/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
@@ -2803,10 +2789,9 @@ static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay
hit->dist = dist;
hit->no[0] = 0.0f;
}
-
}
-/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit normal.
@@ -2915,7 +2900,8 @@ static void dynamicPaint_mixPaintColors(
static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
{
float isect_change = isect_height - wPoint->brush_isect;
- int hit = 0;
+ bool hit = false;
+
/* intersection marked regardless of brush type or hit */
wPoint->brush_isect = isect_height;
wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
@@ -2924,9 +2910,9 @@ static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrush
/* determine hit depending on wave_factor */
if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
- hit = 1;
+ hit = true;
else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
- hit = 1;
+ hit = true;
if (hit) {
if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
@@ -2948,8 +2934,9 @@ static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrush
/*
* add brush results to the surface data depending on surface type
*/
-static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, float timescale)
+static void dynamicPaint_updatePointData(
+ DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
+ float paint[3], float influence, float depth, float vel_factor, float timescale)
{
PaintSurfaceData *sData = surface->data;
float strength;
@@ -2969,9 +2956,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) {
if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
- paint[0] = coba_res[0];
- paint[1] = coba_res[1];
- paint[2] = coba_res[2];
+ copy_v3_v3(paint, coba_res);
}
if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
strength *= coba_res[3];
@@ -2982,12 +2967,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
/* mix paint surface */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
float paintWetness = brush->wetness * strength;
float paintAlpha = strength;
dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, &timescale);
-
}
/* displace surface */
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -3002,10 +2985,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < depth) value[index] = depth;
+ CLAMP_MIN(value[index], depth);
}
}
/* vertex weight group surface */
@@ -3014,10 +2997,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < strength) value[index] = strength;
+ CLAMP_MIN(value[index], strength);
}
}
/* wave surface */
@@ -3026,8 +3009,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
}
- dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index],
- brush, 0.0f - depth);
+ dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
}
/* doing velocity based painting */
@@ -3037,17 +3019,18 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
}
/* checks whether surface and brush bounds intersect depending on brush type */
-static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
+static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
{
if (brush->collision == MOD_DPAINT_COL_VOLUME)
return boundsIntersect(b1, b2);
else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
return boundsIntersectDist(b1, b2, brush_radius);
- else return 1;
+ return true;
}
/* calculate velocity for mesh vertices */
-static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
+static void dynamicPaint_brushMeshCalculateVelocity(
+ Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
int i;
float prev_obmat[4][4];
@@ -3069,7 +3052,8 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_p = CDDM_copy(brush->dm);
numOfVerts_p = dm_p->getNumVerts(dm_p);
mvert_p = dm_p->getVertArray(dm_p);
@@ -3079,13 +3063,15 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_c = brush->dm;
numOfVerts_c = dm_c->getNumVerts(dm_c);
mvert_c = dm_p->getVertArray(dm_c);
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
- if (!(*brushVel)) return;
+ if (!(*brushVel))
+ return;
/* if mesh is constructive -> num of verts has changed,
* only use current frame derived mesh */
@@ -3129,13 +3115,15 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
/* previous frame dm */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
/* current frame dm */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3166,7 +3154,9 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
dynamicPaint_brushMeshCalculateVelocity(scene, brushOb, brush, &brushVelocity, timescale);
- if (!brush->dm) return 0;
+ if (!brush->dm)
+ return 0;
+
{
BVHTreeFromMesh treeData = {NULL};
float avg_brushNor[3] = {0.0f};
@@ -3220,8 +3210,11 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
int id;
/* check grid cell bounding box */
- if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ if (!grid->s_num[c_index] ||
+ !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ {
continue;
+ }
/* loop through cell points and process brush */
#pragma omp parallel for schedule(static)
@@ -3282,7 +3275,9 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* Check volume collision */
if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST)
- if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData) != -1) {
+ BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f,
+ &hit, mesh_tris_spherecast_dp, &treeData);
+ if (hit.index != -1) {
/* We hit a triangle, now check if collision point normal is facing the point */
/* For optimization sake, hit point normal isn't calculated in ray cast loop */
@@ -3308,7 +3303,8 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
hit.index = -1;
hit.dist = BVH_RAYCAST_DIST_MAX;
- BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData);
+ BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f,
+ &hit, mesh_tris_spherecast_dp, &treeData);
if (hit.index != -1) {
/* Add factor on supersample filter */
@@ -3336,7 +3332,9 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* If pure distance proximity, find the nearest point on the mesh */
if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
- if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_tris_nearest_point_dp, &treeData) != -1) {
+ BLI_bvhtree_find_nearest(treeData.tree, ray_start,
+ &nearest, mesh_tris_nearest_point_dp, &treeData);
+ if (nearest.index != -1) {
proxDist = sqrtf(nearest.dist_sq);
copy_v3_v3(hitCo, nearest.co);
tri = nearest.index;
@@ -3359,7 +3357,9 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
hit.dist = brush_radius;
/* Do a face normal directional raycast, and use that distance */
- if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData) != -1) {
+ BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f,
+ &hit, mesh_tris_spherecast_dp, &treeData);
+ if (hit.index != -1) {
proxDist = hit.dist;
madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
tri = hit.index;
@@ -3386,7 +3386,9 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* mix final sample strength depending on brush settings */
if (hit_found) {
/* if "negate volume" enabled, negate all factors within volume*/
- if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
+ if (brush->collision == MOD_DPAINT_COL_VOLDIST &&
+ brush->flags & MOD_DPAINT_NEGATE_VOLUME)
+ {
volume_factor = 1.0f - volume_factor;
if (inner_proximity)
proximity_factor = 1.0f - proximity_factor;
@@ -3398,10 +3400,14 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
}
else if (hit_found == HIT_PROXIMITY) {
/* apply falloff curve to the proximity_factor */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
+ {
proximity_factor = prox_colorband[3];
- else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT)
+ }
+ else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
+ }
/* apply sample */
sampleStrength = proximity_factor;
}
@@ -3466,11 +3472,16 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
sampleColor[2] = brush->b;
/* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index] + ss].v, hitCoord, hitTri, brush->dm);
+ if (brush_usesMaterial(brush, scene)) {
+ dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index] + ss].v,
+ hitCoord, hitTri, dm);
+ }
/* Sample proximity colorband if required */
- if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
+ if ((hit_found == HIT_PROXIMITY) &&
+ (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
+ {
if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
sampleColor[0] = prox_colorband[0];
sampleColor[1] = prox_colorband[1];
@@ -3493,7 +3504,6 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* if any sample was inside paint range */
if (brushStrength > 0.0f || depth > 0.0f) {
-
/* apply supersampling results */
if (samples > 1) {
brushStrength /= total_sample;
@@ -3513,7 +3523,8 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
depth /= bData->bNormal[index].normal_scale * total_sample;
}
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ dynamicPaint_updatePointData(surface, index, brush, paintColor,
+ brushStrength, depth, velocity_val, timescale);
}
}
}
@@ -3550,7 +3561,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
int invalidParticles = 0;
int p = 0;
- float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius);
+ float solidradius = surface->radius_scale *
+ ((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius);
float smooth = brush->particle_smooth * surface->radius_scale;
float range = solidradius + smooth;
@@ -3558,7 +3570,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
Bounds3D part_bb = {0};
- if (psys->totpart < 1) return 1;
+ if (psys->totpart < 1)
+ return 1;
/*
* Build a kd-tree to optimize distance search
@@ -3568,18 +3581,24 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
/* loop through particles and insert valid ones to the tree */
p = 0;
for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
-
/* Proceed only if particle is active */
- if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) continue;
- else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) continue;
- else if (pa->flag & PARS_UNEXIST) continue;
+ if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
+ (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) ||
+ (pa->flag & PARS_UNEXIST))
+ {
+ continue;
+ }
/* for debug purposes check if any NAN particle proceeds
* For some reason they get past activity check, this should rule most of them out */
- if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) { invalidParticles++; continue; }
+ if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
+ invalidParticles++;
+ continue;
+ }
/* make sure particle is close enough to canvas */
- if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) continue;
+ if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
+ continue;
BLI_kdtree_insert(tree, p, pa->state.co);
@@ -3640,7 +3659,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
/* Find nearest particle and get distance to it */
BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
/* if outside maximum range, no other particle can influence either */
- if (nearest.dist > range) continue;
+ if (nearest.dist > range)
+ continue;
if (brush->flags & MOD_DPAINT_PART_RAD) {
/* use particles individual size */
@@ -3721,11 +3741,14 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/* do smoothness if enabled */
- if (smooth_range < 0.0f) smooth_range = 0.0f;
- if (smooth) smooth_range /= smooth;
+ if (smooth_range < 0.0f)
+ smooth_range = 0.0f;
+ if (smooth)
+ smooth_range /= smooth;
str = 1.0f - smooth_range;
/* if influence is greater, use this one */
- if (str > strength) strength = str;
+ if (str > strength)
+ strength = str;
}
}
@@ -3746,8 +3769,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
velocity_val = len_v3(velocity);
/* store brush velocity for smudge */
- if ( (surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
+ if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
{
copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
@@ -3758,8 +3781,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
copy_v3_v3(paintColor, &brush->r);
}
- else if ( (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) ||
- (surface->type == MOD_DPAINT_SURFACE_T_WAVE))
+ else if ((surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE))
{
/* get displace depth */
disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
@@ -3767,7 +3790,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
if (depth < 0.0f) depth = 0.0f;
}
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ dynamicPaint_updatePointData(surface, index, brush, paintColor,
+ strength, depth, velocity_val, timescale);
}
}
}
@@ -3779,8 +3803,9 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/* paint a single point of defined proximity radius to the surface */
-static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+static int dynamicPaint_paintSinglePoint(
+ DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
{
int index;
float brush_radius = brush->paint_distance * surface->radius_scale;
@@ -3800,7 +3825,8 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
float colorband[4] = {0.0f};
float strength;
- if (distance > brush_radius) continue;
+ if (distance > brush_radius)
+ continue;
/* Smooth range or color ramp */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
@@ -3827,12 +3853,16 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
copy_v3_v3(hit_coord, mvert[0].co);
mul_m4_v3(brushOb->obmat, hit_coord);
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
+ dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
}
/* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
+ {
strength = colorband[3];
+ }
if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
float velocity[3];
@@ -3878,7 +3908,7 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
/* get displace depth */
float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale;
- if (depth < 0.0f) depth = 0.0f;
+ CLAMP_MIN(depth, 0.0f);
}
dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
@@ -3893,7 +3923,7 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
/*
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int force_init)
+static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -3902,11 +3932,14 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int
Vec3f *realCoord = bData->realCoord;
int index;
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return;
+ if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
- if (bData->bNeighs) MEM_freeN(bData->bNeighs);
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(struct BakeAdjPoint), "PaintEffectBake");
- if (!bNeighs) return;
+ if (!bNeighs)
+ return;
#pragma omp parallel for schedule(static)
for (index = 0; index < sData->total_points; index++) {
@@ -3922,7 +3955,8 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int
/* dist */
bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir);
/* normalize dir */
- if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
+ if (bNeighs[n_index].dist)
+ mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
}
}
@@ -3940,7 +3974,8 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int
}
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
-static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
+static void surface_determineForceTargetPoints(
+ PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
{
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
int numOfNeighs = sData->adj_data->n_num[index];
@@ -3954,10 +3989,14 @@ static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int inde
int n_index = sData->adj_data->n_index[index] + i;
float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- if (dir_dot > closest_d[0] && dir_dot > 0.0f) { closest_d[0] = dir_dot; closest_id[0] = n_index; }
+ if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
+ closest_d[0] = dir_dot;
+ closest_id[0] = n_index;
+ }
}
- if (closest_d[0] < 0.0f) return;
+ if (closest_d[0] < 0.0f)
+ return;
/* find second closest neigh */
for (i = 0; i < numOfNeighs; i++) {
@@ -3965,7 +4004,8 @@ static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int inde
float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
- if (n_index == closest_id[0]) continue;
+ if (n_index == closest_id[0])
+ continue;
/* only accept neighbor at "other side" of the first one in relation to force dir
* so make sure angle between this and closest neigh is greater than first angle */
@@ -4016,12 +4056,13 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int index, steps, step;
float eff_scale, max_velocity = 0.0f;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/* find max velocity */
for (index = 0; index < sData->total_points; index++) {
float vel = bData->brush_velocity[index * 4 + 3];
- if (vel > max_velocity) max_velocity = vel;
+ CLAMP_MIN(max_velocity, vel);
}
steps = (int)ceil(max_velocity / bData->average_dist * timescale);
@@ -4029,7 +4070,6 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
eff_scale = brush->smudge_strength / (float)steps * timescale;
for (step = 0; step < steps; step++) {
-
for (index = 0; index < sData->total_points; index++) {
int i;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4039,7 +4079,8 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int closest_id[2];
float closest_d[2];
- if (!smudge_str) continue;
+ if (!smudge_str)
+ continue;
/* get force affect points */
surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
@@ -4053,7 +4094,8 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
/* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
+ if (dir_dot <= 0.0f)
+ continue;
dir_factor = dir_dot * speed_scale;
CLAMP_MAX(dir_factor, brush->smudge_strength);
@@ -4076,7 +4118,8 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+static int dynamicPaint_prepareEffectStep(
+ DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -4132,7 +4175,8 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
/* force strength */
(*force)[index * 4 + 3] = len_v3(forc);
/* normalize and copy */
- if ((*force)[index * 4 + 3]) mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
+ if ((*force)[index * 4 + 3])
+ mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
copy_v3_v3(&((*force)[index * 4]), forc);
}
@@ -4166,7 +4210,8 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
/**
* Processes active effect step.
*/
-static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+static void dynamicPaint_doEffectStep(
+ DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
{
PaintSurfaceData *sData = surface->data;
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
@@ -4174,7 +4219,8 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
int index;
timescale /= steps;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/*
* Spread Effect
@@ -4203,17 +4249,20 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
float color_mix = (MIN3(ePoint->wetness, pPoint->wetness, 1.0f)) * 0.25f * surface->color_spread_speed;
/* do color mixing */
- if (color_mix) mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], color_mix);
+ if (color_mix)
+ mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], color_mix);
/* Only continue if surrounding point has higher wetness */
- if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS) continue;
+ if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS)
+ continue;
w_factor = 1.0f / numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale;
CLAMP(w_factor, 0.0f, 1.0f);
/* mix new wetness and color */
pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * ePoint->wetness;
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], w_factor);
+ pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3],
+ w_factor);
}
}
}
@@ -4244,7 +4293,8 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
/* Check if neighboring point has lower alpha,
* if so, decrease this point's alpha as well*/
- if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) continue;
+ if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
+ continue;
/* decrease factor for dry paint alpha */
a_factor = (1.0f - ePoint->color[3]) / numOfNeighs * (pPoint->color[3] - ePoint->color[3]) * speed_scale;
@@ -4284,7 +4334,8 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
/* adjust drip speed depending on wetness */
float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0) continue;
+ if (w_factor <= 0)
+ continue;
CLAMP(w_factor, 0.0f, 1.0f);
/* get force affect points */
@@ -4300,7 +4351,8 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
float e_wet = ePoint->wetness;
/* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
+ if (dir_dot <= 0.0f)
+ continue;
dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
CLAMP_MAX(dir_factor, 0.5f);
@@ -4312,7 +4364,8 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force
/* mix new color */
a_factor = dir_factor / pPoint_prev->wetness;
CLAMP(a_factor, 0.0f, 1.0f);
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
+ mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3],
+ a_factor);
/* dripping is supposed to preserve alpha level */
if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
@@ -4343,7 +4396,8 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
/* allocate memory */
PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
- if (!prevPoint) return;
+ if (!prevPoint)
+ return;
/* calculate average neigh distance (single thread) */
for (index = 0; index < sData->total_points; index++) {
@@ -4367,7 +4421,6 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
for (ss = 0; ss < steps; ss++) {
-
/* copy previous frame data */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
@@ -4379,7 +4432,8 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int numOfN = 0, numOfRN = 0;
int i;
- if (wPoint->state > 0) continue;
+ if (wPoint->state > 0)
+ continue;
/* calculate force from surrounding points */
for (i = 0; i < numOfNeighs; i++) {
@@ -4387,8 +4441,9 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
float dist = bNeighs[n_index].dist * wave_scale;
PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
- if (!dist || tPoint->state > 0) continue;
- if (dist < min_dist) dist = min_dist;
+ if (!dist || tPoint->state > 0)
+ continue;
+ CLAMP_MIN(dist, min_dist);
avg_dist += dist;
numOfN++;
@@ -4408,7 +4463,8 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
{
/* if open borders, apply a fake height to keep waves going on */
avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
- wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) / (avg_dist + dt * wave_speed);
+ wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
+ (avg_dist + dt * wave_speed);
}
/* else do wave eq */
else {
@@ -4427,8 +4483,10 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
if (wave_max_slope && avg_dist) {
float max_offset = wave_max_slope * avg_dist;
float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
- if (offset > max_offset) wPoint->height += offset - max_offset;
- if (offset < -max_offset) wPoint->height += offset + max_offset;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
}
}
}
@@ -4465,8 +4523,10 @@ static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float time
int i;
float dry_ratio, f_color[4];
float p_wetness = pPoint->wetness;
- value_dissolve(&pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG));
- if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
+
+ value_dissolve(&pPoint->wetness, surface->dry_speed, timescale,
+ (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
if (pPoint->wetness < surface->color_dry_threshold) {
dry_ratio = pPoint->wetness / p_wetness;
@@ -4489,7 +4549,8 @@ static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float time
* with these new alpha values. (wet layer color doesnt change)*/
if (pPoint->color[3]) {
for (i = 0; i < 3; i++) {
- pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) / (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
+ pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
}
}
}
@@ -4509,28 +4570,29 @@ static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float time
}
if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
+ value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
CLAMP_MIN(pPoint->color[3], 0.0f);
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
+ value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
CLAMP_MIN(pPoint->e_color[3], 0.0f);
}
}
/* dissolve for float types */
else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
{
float *point = &((float *)sData->type_data)[index];
/* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
+ value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
CLAMP_MIN(*point, 0.0f);
}
}
}
-static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
+static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -4539,50 +4601,26 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
int numOfVerts = dm->getNumVerts(dm);
int i;
- int ret = 0;
+ bool ret = false;
- if (!bData->prev_verts) return 1;
+ if (!bData->prev_verts)
+ return true;
/* matrix comparison */
- for (i = 0; i < 4; i++) {
- int j;
- for (j = 0; j < 4; j++)
- if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1;
- }
+ if (!equals_m4m4(bData->prev_obmat, ob->obmat))
+ return true;
/* vertices */
#pragma omp parallel for schedule(static)
for (i = 0; i < numOfVerts; i++) {
- int j;
- for (j = 0; j < 3; j++)
- if (bData->prev_verts[i].co[j] != mvert[i].co[j]) {
- ret = 1;
- break;
- }
+ if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
+ ret = true;
+ }
}
return ret;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
-{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
-
- if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)
- return 1;
-
- return 0;
-}
-
-static int surface_needsAccelerationData(DynamicPaintSurface *surface)
-{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
-
- return 0;
-}
-
/* Prepare for surface step by creating PaintBakeNormal data */
static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
@@ -4591,15 +4629,16 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
PaintBakeData *bData = sData->bData;
DerivedMesh *dm = surface->canvas->dm;
int index, new_bdata = 0;
- int do_velocity_data = surface_needsVelocityData(surface, scene);
- int do_accel_data = surface_needsAccelerationData(surface);
+ const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
+ (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
int canvasNumOfVerts = dm->getNumVerts(dm);
MVert *mvert = dm->getVertArray(dm);
Vec3f *canvas_verts;
if (bData) {
- int surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
+ const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
/* get previous speed for accelertaion */
if (do_accel_data && bData->prev_velocity && bData->velocity)
@@ -4615,13 +4654,15 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
}
canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (!canvas_verts) return 0;
+ if (!canvas_verts)
+ return 0;
/* allocate memory if required */
if (!bData) {
sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
if (!bData) {
- if (canvas_verts) MEM_freeN(canvas_verts);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return 0;
}
@@ -4634,11 +4675,16 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/* if any allocation failed, free everything */
if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
- if (bData->bNormal) MEM_freeN(bData->bNormal);
- if (bData->s_pos) MEM_freeN(bData->s_pos);
- if (bData->s_num) MEM_freeN(bData->s_num);
- if (bData->realCoord) MEM_freeN(bData->realCoord);
- if (canvas_verts) MEM_freeN(canvas_verts);
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return setError(surface->canvas, N_("Not enough free memory"));
}
@@ -4726,7 +4772,8 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
int t_index = adj_data->n_index[index] + (ss - 1);
/* get vertex position at 1/3 of each neigh edge */
mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
- madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
+ madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
}
}
@@ -4755,8 +4802,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
- interp_v3_v3v3v3(temp_nor,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
+ interp_v3_v3v3v3(temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
}
mul_v3_v3(temp_nor, ob->size);
@@ -4774,7 +4820,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/* generate surface space partitioning grid */
surfaceGenerateGrid(surface);
/* calculate current frame adjacency point distances and global dirs */
- dynamicPaint_prepareAdjacencyData(surface, 0);
+ dynamicPaint_prepareAdjacencyData(surface, false);
/* Copy current frame vertices to check against in next frame */
copy_m4_m4(bData->prev_obmat, ob->obmat);
@@ -4794,7 +4840,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
int ret = 1;
- if (sData->total_points < 1) return 0;
+ if (sData->total_points < 1)
+ return 0;
dynamicPaint_surfacePreStep(surface, timescale);
/*
@@ -4820,24 +4867,23 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
brushObj = NULL;
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
else
brushObj = base->object;
- if (!brushObj) {
- /* skip item */
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
- }
-
/* next item */
if (surface->brush_group)
go = go->next;
else
base = base->next;
+ if (!brushObj) {
+ /* skip item */
+ continue;
+ }
+
/* check if target has an active dp modifier */
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
@@ -4852,15 +4898,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
/* init adjacency data if not already */
if (!sData->adj_data)
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (!bData->bNeighs)
- dynamicPaint_prepareAdjacencyData(surface, 1);
+ dynamicPaint_prepareAdjacencyData(surface, true);
}
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* Prepare materials if required */
if (brush_usesMaterial(brush, scene))
@@ -4869,12 +4916,13 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
/* Apply brush on the surface depending on it's collision type */
/* Particle brush: */
if (brush->collision == MOD_DPAINT_COL_PSYS) {
- if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
psys_check_enabled(brushObj, brush->psys))
{
-
/* Paint a particle system */
- BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
+ BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
}
}
@@ -4894,7 +4942,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* process special brush effects, like smudge */
@@ -4934,8 +4983,10 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
}
/* Free temporary effect data */
- if (prevPoint) MEM_freeN(prevPoint);
- if (force) MEM_freeN(force);
+ if (prevPoint)
+ MEM_freeN(prevPoint);
+ if (force)
+ MEM_freeN(force);
}
}
@@ -4963,7 +5014,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe))
+ return 0;
}
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 96bdfe88722..6c117447664 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_jitter.h"
#include "BLI_bitmap.h"
+#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
@@ -451,118 +452,148 @@ finally:
pRes[3] = fSign;
}
+static void emDM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = emdm_ts_GetPosition;
+ sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = emdm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
/**
* \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
*
* \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
* This is done because #CD_TANGENT is cache data used only for drawing.
*/
-static void emDM_calcLoopTangents(DerivedMesh *dm)
+
+static void emDM_calc_loop_tangents(
+ DerivedMesh *dm, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
BMesh *bm = bmdm->em->bm;
-
- /* mesh vars */
- int cd_loop_uv_offset;
- float (*orco)[3] = NULL, (*tangent)[4];
- int /* totvert, */ totface;
- const float (*fnors)[3];
- const float (*tlnors)[3];
- char htype_index = BM_LOOP;
-
- if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
+ if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
return;
- fnors = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
-
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
-
- /* check we have all the needed layers */
- totface = em->tottri;
-
- cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- /* needed for indexing loop-tangents */
- htype_index = BM_LOOP;
- if (cd_loop_uv_offset == -1) {
- orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!orco)
- return;
- /* needed for orco lookups */
- htype_index |= BM_VERT;
- }
-
- if (fnors) {
- /* needed for face normal lookups */
- htype_index |= BM_FACE;
- }
-
- BM_mesh_elem_index_ensure(bm, htype_index);
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ char tangent_mask = 0;
+
+ DM_calc_loop_tangents_step_0(
+ &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+
+ if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
+ for (int i = 0; i < tangent_names_count; i++)
+ if (tangent_names[i][0])
+ DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
+ if (calc_act && act_uv_name[0])
+ DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
+ int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
- /* create tangent layer */
- DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
- tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+ /* map faces to quads */
+ if (bmdm->em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (bmdm->em->tottri != bm->totface) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (em->looptris[j][0]->f->len == 4) {
- j++; /* skips the nest looptri */
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
}
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
}
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
- }
#endif
-
- /* new computation method */
- {
- SGLSLEditMeshToTangent mesh2tangent = {NULL};
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
-
- mesh2tangent.precomputedFaceNormals = fnors;
- mesh2tangent.precomputedLoopNormals = tlnors;
- mesh2tangent.looptris = (const BMLoop *(*)[3])em->looptris;
- mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset;
- mesh2tangent.orco = (const float (*)[3])orco;
- mesh2tangent.tangent = tangent;
- mesh2tangent.numTessFaces = totface;
-
+ /* Calculation */
+ {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ dm->tangent_mask = 0;
+ /* Calculate tangent layers */
+ SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+ int index = 0;
+ int n = 0;
+ CustomData_update_typemap(&dm->loopData);
+ const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
+ for (n = 0; n < tangent_layer_num; n++) {
+ index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = em->tottri;
#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent.face_as_quad_map = face_as_quad_map;
- mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
+ mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
+ mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+ /* needed for indexing loop-tangents */
+ int htype_index = BM_LOOP;
+ if (mesh2tangent->cd_loop_uv_offset == -1) {
+ mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
+ if (!mesh2tangent->orco)
+ continue;
+ /* needed for orco lookups */
+ htype_index |= BM_VERT;
+ }
+ if (mesh2tangent->precomputedFaceNormals) {
+ /* needed for face normal lookups */
+ htype_index |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype_index);
+
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+ mesh2tangent->tangent = dm->loopData.layers[index].data;
+
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ dm->tangent_mask |= 1 << (uv_ind - uv_start);
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
- sContext.m_pUserData = &mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
-
+ BLI_assert(dm->tangent_mask == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
#ifdef USE_LOOPTRI_DETECT_QUADS
if (face_as_quad_map) {
MEM_freeN(face_as_quad_map);
@@ -570,6 +601,15 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
#undef USE_LOOPTRI_DETECT_QUADS
#endif
}
+ /* Update active layer index */
+ int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
+ CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+
+ /* Update render layer index */
+ uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
+ CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
}
/** \} */
@@ -1419,15 +1459,16 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
}
glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
}
- if (attribs->tottang) {
+
+ for (i = 0; i < attribs->tottang; i++) {
const float *tang;
- if (attribs->tang.em_offset != -1) {
- tang = attribs->tang.array[BM_elem_index_get(loop)];
+ if (attribs->tang[i].em_offset != -1) {
+ tang = attribs->tang[i].array[BM_elem_index_get(loop)];
}
else {
tang = zero;
}
- glVertexAttrib4fv(attribs->tang.gl_index, tang);
+ glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
}
}
@@ -2218,7 +2259,7 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->dm.calcNormals = emDM_calcNormals;
bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
- bmdm->dm.calcLoopTangents = emDM_calcLoopTangents;
+ bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents;
bmdm->dm.recalcTessellation = emDM_recalcTessellation;
bmdm->dm.recalcLoopTri = emDM_recalcLoopTri;
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index ccea2d4ece4..2927354241c 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -544,7 +544,7 @@ BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a, const BMBVHTree *bm
data.tree_pair[0] = bmtree_a;
data.tree_pair[1] = bmtree_b;
- data.epsilon = max_ff(BLI_bvhtree_getepsilon(bmtree_a->tree), BLI_bvhtree_getepsilon(bmtree_b->tree));
+ data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree), BLI_bvhtree_get_epsilon(bmtree_b->tree));
return BLI_bvhtree_overlap(bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 12bce70594b..6284b3a46fb 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -746,13 +746,15 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
copy_v3_v3(tex_co, point->loc);
- if (eff->pd->flag & PFIELD_TEX_2D) {
- float fac=-dot_v3v3(tex_co, efd->nor);
- madd_v3_v3fl(tex_co, efd->nor, fac);
- }
-
if (eff->pd->flag & PFIELD_TEX_OBJECT) {
mul_m4_v3(eff->ob->imat, tex_co);
+
+ if (eff->pd->flag & PFIELD_TEX_2D)
+ tex_co[2] = 0.0f;
+ }
+ else if (eff->pd->flag & PFIELD_TEX_2D) {
+ float fac=-dot_v3v3(tex_co, efd->nor);
+ madd_v3_v3fl(tex_co, efd->nor, fac);
}
scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 11b1bbd64ac..a2b5a05feac 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1600,8 +1600,8 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/* Driver API --------------------------------- */
-/* This frees the driver variable itself */
-void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
+/* Perform actual freeing driver variable and remove it from the given list */
+void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
/* sanity checks */
if (dvar == NULL)
@@ -1621,8 +1621,15 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
DRIVER_TARGETS_LOOPER_END
/* remove the variable from the driver */
- BLI_freelinkN(&driver->variables, dvar);
+ BLI_freelinkN(variables, dvar);
+}
+/* Free the driver variable and do extra updates */
+void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
+
#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
if (driver->type == DRIVER_TYPE_PYTHON)
@@ -1630,6 +1637,24 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
#endif
}
+/* Copy driver variables from src_vars list to dst_vars list */
+void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
+{
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path)
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
@@ -1770,7 +1795,7 @@ void fcurve_free_driver(FCurve *fcu)
/* free driver targets */
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
dvarn = dvar->next;
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
}
#ifdef WITH_PYTHON
@@ -1788,7 +1813,6 @@ void fcurve_free_driver(FCurve *fcu)
ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
{
ChannelDriver *ndriver;
- DriverVar *dvar;
/* sanity checks */
if (driver == NULL)
@@ -1799,19 +1823,8 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
ndriver->expr_comp = NULL;
/* copy variables */
- BLI_listbase_clear(&ndriver->variables);
- BLI_duplicatelist(&ndriver->variables, &driver->variables);
-
- for (dvar = ndriver->variables.first; dvar; dvar = dvar->next) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER(dvar)
- {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path)
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- DRIVER_TARGETS_LOOPER_END
- }
+ BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
+ driver_variables_copy(&ndriver->variables, &driver->variables);
/* return the new driver */
return ndriver;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 0a887dcf676..aed33d2c64d 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -1040,7 +1040,7 @@ makebreak:
timeofs += distfac * cu->xof; /* not cyclic */
ct = chartransdata;
- for (i = 0; i <= slen; i++, ct++) {
+ for (i = 0; i < slen; i++, ct++) {
float ctime, dtime, vec[4], tvec[4], rotvec[3];
float si, co;
@@ -1082,8 +1082,9 @@ makebreak:
sb = &selboxes[i - selstart];
sb->rot = -ct->rot;
}
-
}
+ /* null character is always zero width, no need to iterate over it */
+ chartransdata[slen] = chartransdata[slen - 1];
}
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 485c4f5b29f..f3eb5430bce 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -68,6 +68,7 @@ bool free_gpencil_strokes(bGPDframe *gpf)
/* free stroke memory arrays, then stroke itself */
if (gps->points) MEM_freeN(gps->points);
+ if (gps->triangles) MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
}
@@ -261,6 +262,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ /* high quality fill by default */
+ gpl->flag |= GP_LAYER_HQ_FILL;
+
+ /* default smooth iterations */
+ gpl->draw_smoothlvl = 1;
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
@@ -315,7 +321,8 @@ bGPDframe *gpencil_frame_duplicate(bGPDframe *src)
/* make copy of source stroke, then adjust pointer to points too */
gpsd = MEM_dupallocN(gps);
gpsd->points = MEM_dupallocN(gps->points);
-
+ gpsd->triangles = MEM_dupallocN(gps->triangles);
+ gpsd->flag |= GP_STROKE_RECALC_CACHES;
BLI_addtail(&dst->strokes, gpsd);
}
@@ -424,6 +431,7 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* free the stroke and its data */
MEM_freeN(gps->points);
+ MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
/* if frame has no strokes after this, delete it */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 63cc57d0a21..d4551fd0b2c 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -350,27 +350,41 @@ void BKE_image_free(Image *ima)
}
/* only image block itself */
-static Image *image_alloc(Main *bmain, const char *name, short source, short type)
+static void image_init(Image *ima, short source, short type)
{
- Image *ima;
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ima, id));
- ima = BKE_libblock_alloc(bmain, ID_IM, name);
- if (ima) {
- ima->ok = IMA_OK;
+ ima->ok = IMA_OK;
+
+ ima->xrep = ima->yrep = 1;
+ ima->aspx = ima->aspy = 1.0;
+ ima->gen_x = 1024; ima->gen_y = 1024;
+ ima->gen_type = IMA_GENTYPE_GRID;
- ima->xrep = ima->yrep = 1;
- ima->aspx = ima->aspy = 1.0;
- ima->gen_x = 1024; ima->gen_y = 1024;
- ima->gen_type = 1; /* no defines yet? */
+ ima->source = source;
+ ima->type = type;
- ima->source = source;
- ima->type = type;
+ if (source == IMA_SRC_VIEWER)
+ ima->flag |= IMA_VIEW_AS_RENDER;
- if (source == IMA_SRC_VIEWER)
- ima->flag |= IMA_VIEW_AS_RENDER;
+ BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
+}
- BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
- ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
+void BKE_image_init(struct Image *image)
+{
+ if (image) {
+ image_init(image, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ }
+}
+
+static Image *image_alloc(Main *bmain, const char *name, short source, short type)
+{
+ Image *ima;
+
+ ima = BKE_libblock_alloc(bmain, ID_IM, name);
+ if (ima) {
+ image_init(ima, source, type);
}
return ima;
@@ -828,13 +842,6 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
break;
}
- if (rect_float) {
- /* both byte and float buffers are filling in sRGB space, need to linearize float buffer after BKE_image_buf_fill* functions */
-
- IMB_buffer_float_from_float(rect_float, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB,
- true, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
- }
-
return ibuf;
}
@@ -1992,7 +1999,7 @@ void BKE_image_stamp_buf(
BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
BLF_buffer(mono, rectf, rect, width, height, channels, display);
- BLF_buffer_col(mono, UNPACK4(scene->r.fg_stamp));
+ BLF_buffer_col(mono, scene->r.fg_stamp);
pad = BLF_width_max(mono);
/* use 'h_fixed' rather than 'h', aligns better */
@@ -4494,13 +4501,17 @@ void BKE_image_get_size(Image *image, ImageUser *iuser, int *width, int *height)
ImBuf *ibuf = NULL;
void *lock;
- ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
+ if (image != NULL) {
+ ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
+ }
if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width = ibuf->x;
*height = ibuf->y;
}
- else if (image->type == IMA_TYPE_R_RESULT && iuser != NULL && iuser->scene != NULL) {
+ else if (image != NULL && image->type == IMA_TYPE_R_RESULT &&
+ iuser != NULL && iuser->scene != NULL)
+ {
Scene *scene = iuser->scene;
*width = (scene->r.xsch * scene->r.size) / 100;
*height = (scene->r.ysch * scene->r.size) / 100;
@@ -4514,7 +4525,9 @@ void BKE_image_get_size(Image *image, ImageUser *iuser, int *width, int *height)
*height = IMG_SIZE_FALLBACK;
}
- BKE_image_release_ibuf(image, ibuf, lock);
+ if (image != NULL) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
}
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float size[2])
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 303d0c6adfc..2c8399adece 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -33,30 +33,42 @@
#include "BKE_image.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "BLF_api.h"
-void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
+typedef struct FillColorThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width;
+ float color[4];
+} FillColorThreadData;
+
+static void image_buf_fill_color_slice(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ const float color[4])
{
int x, y;
/* blank image */
if (rect_float) {
+ float linear_color[4];
+ srgb_to_linearrgb_v4(linear_color, color);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- copy_v4_v4(rect_float, color);
+ copy_v4_v4(rect_float, linear_color);
rect_float += 4;
}
}
}
-
+
if (rect) {
unsigned char ccol[4];
-
rgba_float_to_uchar(ccol, color);
-
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
-
rect[0] = ccol[0];
rect[1] = ccol[1];
rect[2] = ccol[2];
@@ -67,37 +79,79 @@ void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width,
}
}
+static void image_buf_fill_color_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillColorThreadData *data = (FillColorThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_color_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ data->color);
+}
-void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
+void BKE_image_buf_fill_color(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ const float color[4])
{
- /* these two passes could be combined into one, but it's more readable and
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_color_slice(rect, rect_float, width, height, color);
+ }
+ else {
+ FillColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ copy_v4_v4(data.color, color);
+ IMB_processor_apply_threaded_scanlines(
+ height, image_buf_fill_color_thread_do, &data);
+ }
+}
+
+static void image_buf_fill_checker_slice(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ int offset)
+{
+ /* these two passes could be combined into one, but it's more readable and
* easy to tweak like this, speed isn't really that much of an issue in this situation... */
-
+
int checkerwidth = 32, dark = 1;
int x, y;
unsigned char *rect_orig = rect;
float *rect_float_orig = rect_float;
-
+
float h = 0.0, hoffs = 0.0;
float hsv[3] = {0.0f, 0.9f, 0.9f};
float rgb[3];
+ float dark_linear_color, bright_linear_color;
+ if (rect_float != NULL) {
+ dark_linear_color = srgb_to_linearrgb(0.25f);
+ bright_linear_color = srgb_to_linearrgb(0.58f);
+ }
+
/* checkers */
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
dark = powf(-1.0f, floorf(y / checkerwidth));
-
+
for (x = 0; x < width; x++) {
if (x % checkerwidth == 0) dark = -dark;
-
+
if (rect_float) {
if (dark > 0) {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.25f;
+ rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
rect_float[3] = 1.0f;
}
else {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.58f;
+ rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
rect_float[3] = 1.0f;
}
rect_float += 4;
@@ -120,12 +174,12 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
rect_float = rect_float_orig;
/* 2nd pass, colored + */
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
hoffs = 0.125f * floorf(y / checkerwidth);
-
+
for (x = 0; x < width; x++) {
h = 0.125f * floorf(x / checkerwidth);
-
+
if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
(abs((y % checkerwidth) - (checkerwidth / 2)) < 4))
{
@@ -134,18 +188,16 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
{
hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
hsv_to_rgb_v(hsv, rgb);
-
+
if (rect) {
rect[0] = (char)(rgb[0] * 255.0f);
rect[1] = (char)(rgb[1] * 255.0f);
rect[2] = (char)(rgb[2] * 255.0f);
rect[3] = 255;
}
-
+
if (rect_float) {
- rect_float[0] = rgb[0];
- rect_float[1] = rgb[1];
- rect_float[2] = rgb[2];
+ srgb_to_linearrgb_v3_v3(rect_float, rgb);
rect_float[3] = 1.0f;
}
}
@@ -157,13 +209,55 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
}
}
+typedef struct FillCheckerThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width;
+} FillCheckerThreadData;
+
+static void image_buf_fill_checker_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillCheckerThreadData *data = (FillCheckerThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_checker_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ start_scanline);
+}
+
+void BKE_image_buf_fill_checker(unsigned char *rect,
+ float *rect_float,
+ int width, int height)
+{
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
+ }
+ else {
+ FillCheckerThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ IMB_processor_apply_threaded_scanlines(
+ height, image_buf_fill_checker_thread_do, &data);
+ }
+}
/* Utility functions for BKE_image_buf_fill_checker_color */
#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
#define BLEND_CHAR(real, add) ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
-static void checker_board_color_fill(unsigned char *rect, float *rect_float, int width, int height)
+static void checker_board_color_fill(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int offset,
+ int total_height)
{
int hue_step, y, x;
float hsv[3], rgb[3];
@@ -173,9 +267,9 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
hue_step = power_of_2_max_i(width / 8);
if (hue_step < 8) hue_step = 8;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
- hsv[2] = 0.1 + (y * (0.4 / height)); /* use a number lower then 1.0 else its too bright */
+ hsv[2] = 0.1 + (y * (0.4 / total_height)); /* use a number lower then 1.0 else its too bright */
for (x = 0; x < width; x++) {
hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
hsv_to_rgb_v(hsv, rgb);
@@ -185,7 +279,7 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
rect[1] = (char)(rgb[1] * 255.0f);
rect[2] = (char)(rgb[2] * 255.0f);
rect[3] = 255;
-
+
rect += 4;
}
@@ -194,27 +288,35 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
rect_float[1] = rgb[1];
rect_float[2] = rgb[2];
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
}
}
-static void checker_board_color_tint(unsigned char *rect, float *rect_float, int width, int height, int size, float blend)
+static void checker_board_color_tint(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int size,
+ float blend,
+ int offset)
{
int x, y;
float blend_half = blend * 0.5f;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
for (x = 0; x < width; x++) {
- if (((y / size) % 2 == 1 && (x / size) % 2 == 1) || ( (y / size) % 2 == 0 && (x / size) % 2 == 0)) {
+ if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
+ ((y / size) % 2 == 0 && (x / size) % 2 == 0))
+ {
if (rect) {
rect[0] = (char)BLEND_CHAR(rect[0], blend);
rect[1] = (char)BLEND_CHAR(rect[1], blend);
rect[2] = (char)BLEND_CHAR(rect[2], blend);
rect[3] = 255;
-
+
rect += 4;
}
if (rect_float) {
@@ -222,7 +324,7 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
@@ -232,7 +334,7 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
rect[3] = 255;
-
+
rect += 4;
}
if (rect_float) {
@@ -240,19 +342,24 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
-
+
}
}
}
-static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int width, int height, float blend)
+static void checker_board_grid_fill(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ float blend,
+ int offset)
{
int x, y;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
for (x = 0; x < width; x++) {
if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
if (rect) {
@@ -268,7 +375,7 @@ static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
@@ -282,7 +389,12 @@ static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int
/* defined in image.c */
-static void checker_board_text(unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
+static void checker_board_text(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int step,
+ int outline)
{
int x, y;
int pen_x, pen_y;
@@ -297,6 +409,9 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width
*/
BLF_buffer(mono, rect_float, rect, width, height, 4, NULL);
+ const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
+ const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
+
for (y = 0; y < height; y += step) {
text[1] = '1';
@@ -306,7 +421,7 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width
pen_y = y + 44;
/* terribly crappy outline font! */
- BLF_buffer_col(mono, 1.0, 1.0, 1.0, 1.0);
+ BLF_buffer_col(mono, text_outline);
BLF_position(mono, pen_x - outline, pen_y, 0.0);
BLF_draw_buffer(mono, text, 2);
@@ -326,7 +441,7 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width
BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
BLF_draw_buffer(mono, text, 2);
- BLF_buffer_col(mono, 0.0, 0.0, 0.0, 1.0);
+ BLF_buffer_col(mono, text_color);
BLF_position(mono, pen_x, pen_y, 0.0);
BLF_draw_buffer(mono, text, 2);
@@ -339,14 +454,71 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width
BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
}
+static void checker_board_color_prepare_slice(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int offset,
+ int total_height)
+{
+ checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
+ checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
+ checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
+}
+
+typedef struct FillCheckerColorThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width, height;
+} FillCheckerColorThreadData;
+
+static void checker_board_color_prepare_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillCheckerColorThreadData *data = (FillCheckerColorThreadData *)data_v;
+ size_t offset = ((size_t)data->width) * start_scanline * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ checker_board_color_prepare_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ start_scanline,
+ data->height);
+}
+
void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
{
- checker_board_color_fill(rect, rect_float, width, height);
- checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f);
- checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f);
- checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f);
- checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f);
- checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f);
+ if (((size_t)width) * height < 64 * 64) {
+ checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
+ }
+ else {
+ FillCheckerColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ data.height = height;
+ IMB_processor_apply_threaded_scanlines(
+ height, checker_board_color_prepare_thread_do, &data);
+ }
checker_board_text(rect, rect_float, width, height, 128, 2);
+
+ if (rect_float != NULL) {
+ /* TODO(sergey): Currently it's easier to fill in form buffer and
+ * linearize it afterwards. This could be optimized with some smart
+ * trickery around blending factors and such.
+ */
+ IMB_buffer_float_from_float_threaded(rect_float, rect_float,
+ 4,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_SRGB,
+ true,
+ width, height,
+ width, width);
+ }
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 57c02ec6329..b350e932281 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -1082,6 +1082,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
md->scene = scene;
+ if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 895d215ca91..961b45df4e6 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -931,7 +931,7 @@ void BKE_libblock_init_empty(ID *id)
BKE_texture_default((Tex *)id);
break;
case ID_IM:
- /* Image is a bit complicated, for now assume NULLified im is OK. */
+ BKE_image_init((Image *)id);
break;
case ID_LT:
BKE_lattice_init((Lattice *)id);
@@ -1783,7 +1783,7 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
-static void lib_indirect_test_id(ID *id, Library *lib)
+static void lib_indirect_test_id(ID *id, const Library *lib)
{
#define LIBTAG(a) \
if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
@@ -1830,9 +1830,14 @@ static void lib_indirect_test_id(ID *id, Library *lib)
#undef LIBTAG
}
-/* if lib!=NULL, only all from lib local
- * bmain is almost certainly G.main */
-void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only, bool set_fake)
+/** Make linked datablocks local.
+ *
+ * \param bmain Almost certainly G.main.
+ * \param lib If not NULL, only make local datablocks from this library.
+ * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
+ * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
+ */
+void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
ID *id, *idn;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 12db3a87ba0..930a3c487ec 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -116,7 +116,7 @@ MaskSplinePoint *BKE_mask_spline_point_array(MaskSpline *spline)
return spline->points_deform ? spline->points_deform : spline->points;
}
-MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline, MaskSplinePoint *point_ref)
+MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline, const MaskSplinePoint *point_ref)
{
if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) {
return spline->points;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 809b45d4b36..1fec725dbb7 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1148,7 +1148,7 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
/* parses the geom+tex nodes */
ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
-
+ basemat->nmap_tangent_names_count = 0;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id) {
if (GS(node->id->name) == ID_MA) {
@@ -1170,6 +1170,21 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
else if (node->type == NODE_GROUP)
init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb);
}
+ else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
+ basemat->mode2_l |= MA_TANGENT_CONCRETE;
+ NodeShaderNormalMap *nm = node->storage;
+ bool taken_into_account = false;
+ for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
+ if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
+ taken_into_account = true;
+ break;
+ }
+ }
+ if (!taken_into_account) {
+ BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
+ strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
+ }
+ }
}
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c10592882c0..2af78cca79f 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -595,14 +595,17 @@ Mesh *BKE_mesh_copy(Mesh *me)
return BKE_mesh_copy_ex(G.main, me);
}
-BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
+BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
bm = BM_mesh_create(&allocsize);
- BM_mesh_bm_from_me(bm, me, false, true, ob->shapenr);
+ BM_mesh_bm_from_me(
+ bm, me, (&(struct BMeshFromMeshParams){
+ .add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr,
+ }));
return bm;
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 83e020cf2ea..577a21285f8 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2417,30 +2417,42 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
}
}
-void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
+void BKE_mesh_tangent_loops_to_tessdata(
+ CustomData *fdata, CustomData *ldata, MFace *mface,
+ int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name)
{
/* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
* Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
* this. Better imho to live with it for now. :/ --mont29
*/
- const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+
+ float (*ftangents)[4] = NULL;
+ float (*ltangents)[4] = NULL;
+
int findex, j;
const int *pidx;
unsigned int (*lidx)[4];
- if (hasLoopTangent) {
- /* need to do for all uv maps at some point */
- float (*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- float (*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+ if (layer_name)
+ ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
+ else
+ ltangents = CustomData_get_layer(ldata, CD_TANGENT);
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++)
- {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ if (ltangents) {
+ /* need to do for all uv maps at some point */
+ if (layer_name)
+ ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
+ else
+ ftangents = CustomData_get_layer(fdata, CD_TANGENT);
+ if (ftangents) {
+ for (findex = 0, pidx = polyindices, lidx = loopindices;
+ findex < num_faces;
+ pidx++, lidx++, findex++)
+ {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 49dd0b104ab..ba890b005d8 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -284,7 +284,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
bool fix_normal = true;
for (j = 0; j < 3; j++) {
- if (!finite(mv->co[j])) {
+ if (!isfinite(mv->co[j])) {
PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);
if (do_fixes) {
@@ -765,7 +765,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
/* note, greater than max defgroups is accounted for in our code, but not < 0 */
- if (!finite(dw->weight)) {
+ if (!isfinite(dw->weight)) {
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
dw->weight = 0.0f;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 1ba4852623c..65ee153e00b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -244,6 +244,11 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
+ return false;
+ }
+
if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
(ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh))))
{
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 7f742dee73c..63c37fddc60 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -1253,15 +1253,16 @@ DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
"DupliObject apply extra data");
for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* copy obmat from duplis */
- copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
-
/* make sure derivedmesh is calculated once, before drawing */
if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
dob->ob->transflag |= OB_DUPLICALCDERIVED;
}
+ }
+ for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
+ /* copy obmat from duplis */
+ copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
copy_m4_m4(dob->ob->obmat, dob->mat);
/* copy layers from the main duplicator object */
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 1b6fc92ef5e..3a2663c5d48 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -635,7 +635,7 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
}
if (reorder)
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
- BM_mesh_bm_to_me(ss->bm, ob->data, false);
+ BM_mesh_bm_to_me(ss->bm, ob->data, (&(struct BMeshToMeshParams){0}));
}
}
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 098700495a0..7dce237c737 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -4225,8 +4225,8 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
/* can happen with bad pointcache or physics calculation
* since this becomes geometry, nan's and inf's crash raytrace code.
* better not allow this. */
- if ((!finite(bb->vec[0])) || (!finite(bb->vec[1])) || (!finite(bb->vec[2])) ||
- (!finite(bb->vel[0])) || (!finite(bb->vel[1])) || (!finite(bb->vel[2])) )
+ if ((!isfinite(bb->vec[0])) || (!isfinite(bb->vec[1])) || (!isfinite(bb->vec[2])) ||
+ (!isfinite(bb->vel[0])) || (!isfinite(bb->vel[1])) || (!isfinite(bb->vel[2])) )
{
zero_v3(bb->vec);
zero_v3(bb->vel);
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 9185c0964b9..f6bddfa6f99 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -390,23 +390,26 @@ static void psys_uv_to_w(float u, float v, int quad, float *w)
/* Find the index in "sum" array before "value" is crossed. */
static int distribute_binary_search(float *sum, int n, float value)
{
- int mid, low=0, high=n;
+ int mid, low = 0, high = n - 1;
- if (value == 0.f)
- return 0;
+ if (sum[low] >= value)
+ return low;
+
+ if (sum[high] < value)
+ return high;
- while (low <= high) {
- mid= (low + high)/2;
+ while (low < high) {
+ mid = (low + high) / 2;
- if (sum[mid] < value && value <= sum[mid+1])
+ if ((sum[mid] < value) && (sum[mid + 1] >= value))
return mid;
- if (sum[mid] >= value)
- high= mid - 1;
- else if (sum[mid] < value)
- low= mid + 1;
- else
- return mid;
+ if (sum[mid] >= value) {
+ high = mid - 1;
+ }
+ else if (sum[mid] < value) {
+ low = mid + 1;
+ }
}
return low;
@@ -778,7 +781,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int cfrom=0;
int totelem=0, totpart, *particle_element=0, children=0, totseam=0;
int jitlevel= 1, distr;
- float *element_weight=NULL,*element_sum=NULL,*jitter_offset=NULL, *vweight=NULL;
+ float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
if (ELEM(NULL, ob, psys, psys->part))
@@ -915,7 +918,6 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
element_weight = MEM_callocN(sizeof(float)*totelem, "particle_distribution_weights");
particle_element= MEM_callocN(sizeof(int)*totpart, "particle_distribution_indexes");
- element_sum = MEM_mallocN(sizeof(*element_sum) * totelem, "particle_distribution_sum");
jitter_offset = MEM_callocN(sizeof(float)*totelem, "particle_distribution_jitoff");
/* Calculate weights from face areas */
@@ -1003,27 +1005,55 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Calculate total weight of all elements */
- totweight= 0.0f;
- for (i=0;i<totelem; i++)
+ int totmapped = 0;
+ totweight = 0.0f;
+ for (i = 0; i < totelem; i++) {
+ if (element_weight[i] != 0.0f) {
+ totmapped++;
+ }
totweight += element_weight[i];
+ }
+
+ if (totweight == 0.0f) {
+ /* We are not allowed to distribute particles anywhere... */
+ return 0;
+ }
inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
- /* Calculate cumulative weights */
- element_sum[0] = element_weight[0] * inv_totweight;
- for (i = 1; i < totelem; i++) {
- element_sum[i] = element_sum[i - 1] + element_weight[i] * inv_totweight;
+ /* Calculate cumulative weights.
+ * We remove all null-weighted elements from element_sum, and create a new mapping
+ * 'activ'_elem_index -> orig_elem_index.
+ * This simplifies greatly the filtering of zero-weighted items - and can be much mor efficient
+ * especially in random case (reducing a lot the size of binary-searched array)...
+ */
+ float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
+ int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__);
+ int i_mapped = 0;
+
+ for (i = 0; i < totelem && element_weight[i] == 0.0f; i++);
+ element_sum[i_mapped] = element_weight[i] * inv_totweight;
+ element_map[i_mapped] = i;
+ i_mapped++;
+ for (i++; i < totelem; i++) {
+ if (element_weight[i] != 0.0f) {
+ element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
+ element_map[i_mapped] = i;
+ i_mapped++;
+ }
}
+
+ BLI_assert(i_mapped == totmapped);
/* Finally assign elements to particles */
- if ((part->flag&PART_TRAND) || (part->simplify_flag&PART_SIMPLIFY_ENABLE)) {
+ if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
float pos;
- for (p=0; p<totpart; p++) {
- /* In theory element_sum[totelem] should be 1.0, but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos= BLI_frand() * element_sum[totelem - 1];
- particle_element[p] = distribute_binary_search(element_sum, totelem, pos);
- particle_element[p] = MIN2(totelem-1, particle_element[p]);
+ for (p = 0; p < totpart; p++) {
+ /* In theory element_sum[totelem - 1] should be 1.0,
+ * but due to float errors this is not necessarily always true, so scale pos accordingly. */
+ pos = BLI_frand() * element_sum[totmapped - 1];
+ particle_element[p] = element_map[distribute_binary_search(element_sum, totmapped, pos)];
jitter_offset[particle_element[p]] = pos;
}
}
@@ -1036,31 +1066,23 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
* 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
* and avoid stumbling over float imprecisions in element_sum. */
if (from == PART_FROM_VERT) {
- pos = (totpart < totelem) ? 0.5 / (double)totelem : step * 0.5; /* We choose the smaller step. */
+ pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
}
else {
pos = 0.0;
}
- /* Avoid initial zero-weight items. */
- for (i = 0; (element_sum[i] == 0.0) && (i < totelem - 1); i++);
-
- for (p = 0; p < totpart; p++, pos += step) {
- for ( ; (pos > (double)element_sum[i]) && (i < totelem - 1); i++);
+ for (i = 0, p = 0; p < totpart; p++, pos += step) {
+ for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++);
- particle_element[p] = i;
+ particle_element[p] = element_map[i];
jitter_offset[particle_element[p]] = pos;
}
-
- /* Avoid final zero weight items. */
- BLI_assert(p == totpart);
- if (element_weight[particle_element[--p]] == 0.0f) {
- particle_element[p] = particle_element[p - 1];
- }
}
MEM_freeN(element_sum);
+ MEM_freeN(element_map);
/* For hair, sort by origindex (allows optimization's in rendering), */
/* however with virtual parents the children need to be in random order. */
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 330b5922c9a..d73f087a3fe 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -979,16 +979,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- /* Atomic float addition.
- * Note that since collision are unlikely, loop will nearly always run once. */
- float oldval, newval;
- uint32_t prevval;
- do {
- oldval = vnors[v][k];
- newval = oldval + fn[k];
- prevval = atomic_cas_uint32(
- (uint32_t *)&vnors[v][k], *(uint32_t *)(&oldval), *(uint32_t *)(&newval));
- } while (UNLIKELY(prevval != *(uint32_t *)(&oldval)));
+ atomic_add_fl(&vnors[v][k], fn[k]);
}
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 448aaaa7830..f0ba63e35b4 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -59,7 +59,6 @@
#include "BKE_appdir.h"
#include "BKE_anim.h"
-#include "BKE_blender.h"
#include "BKE_cloth.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 6b297a143d6..27abbb62762 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -101,11 +101,6 @@
#include "bmesh.h"
-#ifdef WIN32
-#else
-# include <sys/time.h>
-#endif
-
const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
const char *RE_engine_id_CYCLES = "CYCLES";
@@ -616,6 +611,12 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
+ sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
+ sce->toolsettings->curve_paint_settings.error_threshold = 8;
+ sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
+ sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
+
sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
sce->toolsettings->statvis.overhang_min = 0;
sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
@@ -1768,7 +1769,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
{
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
- BM_mesh_bm_to_me(bm, mesh, false);
+ BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0}));
DAG_id_tag_update(&mesh->id, 0);
}
}
@@ -2423,7 +2424,6 @@ SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd,
if ((rd->scemode & R_MULTIVIEW) == 0)
return NULL;
- nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (nr++ == view_id)
@@ -2454,7 +2454,6 @@ int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
if ((!viewname) || (!viewname[0]))
return 0;
- nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (STREQ(viewname, srv->name)) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 1b807adca4b..3de4a426973 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3060,7 +3060,7 @@ static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
ibuf1 = out;
init_data.ibuf = ibuf1;
- out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);;
+ out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
init_data.out = out;
IMB_processor_apply_threaded(out->y,
@@ -3084,6 +3084,10 @@ static void init_text_effect(Sequence *seq)
data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars");
data->text_size = 30;
+
+ copy_v4_fl(data->color, 1.0f);
+ data->shadow_color[3] = 1.0f;
+
BLI_strncpy(data->text, "Text", sizeof(data->text));
data->loc[0] = 0.5f;
@@ -3099,7 +3103,9 @@ static int num_inputs_text(void)
static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
{
TextVars *data = seq->effectdata;
- if (data->text[0] == 0 || data->text_size < 1) {
+ if (data->text[0] == 0 || data->text_size < 1 ||
+ ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0)))
+ {
return EARLY_USE_INPUT_1;
}
return EARLY_NO_INPUT;
@@ -3188,11 +3194,11 @@ static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float
fontx = BLF_width_max(mono);
fonty = line_height;
BLF_position(mono, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0f);
- BLF_buffer_col(mono, 0.0f, 0.0f, 0.0f, 1.0f);
+ BLF_buffer_col(mono, data->shadow_color);
BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX);
}
BLF_position(mono, x, y, 0.0f);
- BLF_buffer_col(mono, 1.0f, 1.0f, 1.0f, 1.0f);
+ BLF_buffer_col(mono, data->color);
BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX);
BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index badf78edfb1..e855f6faa22 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -245,11 +245,11 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* for finding the best hit, to get the real dist,
* measure the len_v3v3() from the input coord to hit.co */
BVHTreeRayHit hit;
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
+ void *treeData = NULL;
/* auxiliary target */
DerivedMesh *auxMesh = NULL;
- BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh;
+ void *auxData = NULL;
SpaceTransform local2aux;
/* If the user doesn't allows to project in any direction of projection axis
@@ -285,19 +285,44 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
/* use editmesh to avoid array allocation */
+ BMEditMesh *emtarget = NULL, *emaux = NULL;
+ BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack;
+ BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack;
+ BVHTree *targ_tree;
+ void *targ_callback;
if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
- treeData.em_evil = BKE_editmesh_from_object(calc->smd->target);
- treeData.em_evil_all = true;
+ emtarget = BKE_editmesh_from_object(calc->smd->target);
+ if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) {
+ targ_callback = emtreedata_stack.raycast_callback;
+ treeData = &emtreedata_stack;
+ }
}
- if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
- auxData.em_evil = BKE_editmesh_from_object(calc->smd->auxTarget);
- auxData.em_evil_all = true;
+ else {
+ if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) {
+ targ_callback = dmtreedata_stack.raycast_callback;
+ treeData = &dmtreedata_stack;
+ }
}
-
- /* After sucessufuly build the trees, start projection vertexs */
- if (bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 4, 6) &&
- (auxMesh == NULL || bvhtree_from_mesh_looptri(&auxData, auxMesh, 0.0, 4, 6)))
- {
+ if (targ_tree) {
+ BVHTree *aux_tree = NULL;
+ void *aux_callback;
+ if (auxMesh != NULL) {
+ /* use editmesh to avoid array allocation */
+ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
+ emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
+ if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) {
+ aux_callback = emauxdata_stack.raycast_callback;
+ auxData = &emauxdata_stack;
+ }
+ }
+ else {
+ if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) {
+ aux_callback = dmauxdata_stack.raycast_callback;
+ auxData = &dmauxdata_stack;
+ }
+ }
+ }
+ /* After sucessufuly build the trees, start projection vertexs */
#ifndef __APPLE__
#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
@@ -340,15 +365,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* Project over positive direction of axis */
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
- if (auxData.tree) {
- BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no,
- &local2aux, auxData.tree, &hit,
- auxData.raycast_callback, &auxData);
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no,
+ &local2aux, aux_tree, &hit,
+ aux_callback, auxData);
}
- BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no,
- &calc->local2target, treeData.tree, &hit,
- treeData.raycast_callback, &treeData);
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no,
+ &calc->local2target, targ_tree, &hit,
+ targ_callback, treeData);
}
/* Project over negative direction of axis */
@@ -356,15 +383,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
float inv_no[3];
negate_v3_v3(inv_no, tmp_no);
- if (auxData.tree) {
- BKE_shrinkwrap_project_normal(0, tmp_co, inv_no,
- &local2aux, auxData.tree, &hit,
- auxData.raycast_callback, &auxData);
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no,
+ &local2aux, aux_tree, &hit,
+ aux_callback, auxData);
}
- BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no,
- &calc->local2target, treeData.tree, &hit,
- treeData.raycast_callback, &treeData);
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, inv_no,
+ &calc->local2target, targ_tree, &hit,
+ targ_callback, treeData);
}
/* don't set the initial dist (which is more efficient),
@@ -383,8 +412,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
/* free data structures */
- free_bvhtree_from_mesh(&treeData);
- free_bvhtree_from_mesh(&auxData);
+ if (treeData) {
+ if (emtarget) free_bvhtree_from_editmesh(treeData);
+ else free_bvhtree_from_mesh(treeData);
+ }
+ if (auxData) {
+ if (emaux) free_bvhtree_from_editmesh(auxData);
+ else free_bvhtree_from_mesh(auxData);
+ }
}
/*
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
index 0d355abb49b..6f5c264f658 100644
--- a/source/blender/blenkernel/intern/sketch.c
+++ b/source/blender/blenkernel/intern/sketch.c
@@ -50,8 +50,6 @@ void freeSketch(SK_Sketch *sketch)
sk_freeStroke(stk);
}
- BLI_freelistN(&sketch->depth_peels);
-
MEM_freeN(sketch);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 97994332411..a84b8352417 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3016,11 +3016,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
numdata++;
}
}
- if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
+ for (b = 0; b < matconv[a].attribs.tottang; b++) {
+ if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].size = 4;
+ matconv[a].datatypes[numdata].type = GL_FLOAT;
+ numdata++;
+ }
}
if (numdata != 0) {
matconv[a].numdata = numdata;
@@ -3105,15 +3107,17 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
offset += sizeof(unsigned char) * 4;
}
}
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array + tot_loops;
+ for (b = 0; b < matconv[i].attribs.tottang; b++) {
+ if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
+ const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
- copy_v4_v4((float *)&varray[offset], looptang[0]);
- copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
- copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
- copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
+ copy_v4_v4((float *)&varray[offset], looptang[0]);
+ copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
+ copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
+ copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
- offset += sizeof(float) * 4;
+ offset += sizeof(float) * 4;
+ }
}
tot_loops += 4;
@@ -4361,6 +4365,7 @@ static void ccgDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm)
{
+ BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
if (dm->looptris.array) {
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
}
@@ -4391,6 +4396,7 @@ static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm)
lt->poly = poly_index;
}
}
+ BLI_rw_mutex_unlock(&loops_cache_rwlock);
return dm->looptris.array;
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index cf11fe2323d..c0a373395dc 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -102,7 +102,7 @@ typedef struct bUnitDef {
/* define a single unit */
typedef struct bUnitCollection {
- struct bUnitDef *units;
+ const struct bUnitDef *units;
int base_unit; /* basic unit index (when user doesn't specify unit explicitly) */
int flag; /* options for this system */
int length; /* to quickly find the last item */
@@ -113,7 +113,7 @@ static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, 1.0, 0.0}, {N
static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)};
/* Lengths */
-static struct bUnitDef buMetricLenDef[] = {
+static const struct bUnitDef buMetricLenDef[] = {
{"kilometer", "kilometers", "km", NULL, "Kilometers", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
{"hectometer", "hectometers", "hm", NULL, "100 Meters", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
{"dekameter", "dekameters", "dam", NULL, "10 Meters", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
@@ -131,7 +131,7 @@ static struct bUnitDef buMetricLenDef[] = {
#endif
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
+static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
static struct bUnitDef buImperialLenDef[] = {
{"mile", "miles", "mi", "m", "Miles", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
@@ -289,7 +289,7 @@ static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, siz
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
-static struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
+static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
{NULL, NULL, NULL, NULL, NULL, &buNaturalRotCollection, &buNaturalTimeCollection, NULL, NULL, NULL},
{NULL, &buMetricLenCollection, &buMetricAreaCollection, &buMetricVolCollection, &buMetricMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buMetricVelCollection, &buMetricAclCollection, &buCameraLenCollection}, /* metric */
{NULL, &buImperialLenCollection, &buImperialAreaCollection, &buImperialVolCollection, &buImperialMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buImperialVelCollection, &buImperialAclCollection, &buCameraLenCollection}, /* imperial */
@@ -299,20 +299,21 @@ static struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
/* internal, has some option not exposed */
-static bUnitCollection *unit_get_system(int system, int type)
+static const bUnitCollection *unit_get_system(int system, int type)
{
assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT));
return bUnitSystems[system][type]; /* select system to use, metric/imperial/other? */
}
-static bUnitDef *unit_default(bUnitCollection *usys)
+static const bUnitDef *unit_default(const bUnitCollection *usys)
{
return &usys->units[usys->base_unit];
}
-static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *unit_start, int suppress)
+static const bUnitDef *unit_best_fit(
+ double value, const bUnitCollection *usys, const bUnitDef *unit_start, int suppress)
{
- bUnitDef *unit;
+ const bUnitDef *unit;
double value_abs = value > 0.0 ? value : -value;
for (unit = unit_start ? unit_start : usys->units; unit->name; unit++) {
@@ -337,19 +338,21 @@ static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *un
}
/* convert into 2 units and 2 values for "2ft, 3inch" syntax */
-static void unit_dual_convert(double value, bUnitCollection *usys, bUnitDef **unit_a, bUnitDef **unit_b,
- double *value_a, double *value_b)
+static void unit_dual_convert(
+ double value, const bUnitCollection *usys,
+ bUnitDef const **r_unit_a, bUnitDef const **r_unit_b,
+ double *r_value_a, double *r_value_b)
{
- bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
+ const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
- *value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
- *value_b = value - (*value_a);
+ *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
+ *r_value_b = value - (*r_value_a);
- *unit_a = unit;
- *unit_b = unit_best_fit(*value_b, usys, *unit_a, 1);
+ *r_unit_a = unit;
+ *r_unit_b = unit_best_fit(*r_value_b, usys, *r_unit_a, 1);
}
-static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys,
+static size_t unit_as_string(char *str, int len_max, double value, int prec, const bUnitCollection *usys,
/* non exposed options */
const bUnitDef *unit, char pad)
{
@@ -422,14 +425,14 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn
*/
size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
if (usys == NULL || usys->units[0].name == NULL)
usys = &buDummyCollection;
/* split output makes sense only for length, mass and time */
if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) {
- bUnitDef *unit_a, *unit_b;
+ const bUnitDef *unit_a, *unit_b;
double value_a, value_b;
unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b);
@@ -522,7 +525,7 @@ static bool ch_is_op(char op)
}
}
-static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit,
+static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit,
const char *replace_str)
{
char *str_found;
@@ -571,7 +574,7 @@ static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pr
return 0;
}
-static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit)
+static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
{
int ofs = 0;
ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_short);
@@ -581,7 +584,7 @@ static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref
return ofs;
}
-static bool unit_find(const char *str, bUnitDef *unit)
+static bool unit_find(const char *str, const bUnitDef *unit)
{
if (unit_find_str(str, unit->name_short)) return true;
if (unit_find_str(str, unit->name_plural)) return true;
@@ -591,12 +594,12 @@ static bool unit_find(const char *str, bUnitDef *unit)
return false;
}
-static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, const char *str_prev)
+static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev)
{
/* Try to find a default unit from current or previous string.
* This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
* Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
- bUnitDef *unit = NULL;
+ const bUnitDef *unit = NULL;
/* see which units the new value has */
for (unit = usys->units; unit->name; unit++) {
@@ -636,9 +639,9 @@ static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, co
*/
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit = NULL, *default_unit;
+ const bUnitDef *unit = NULL, *default_unit;
double scale_pref_base = scale_pref;
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
@@ -679,7 +682,7 @@ bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sc
* In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
* I do think this is the desired behavior!
*/
- bUnitCollection *usys_iter;
+ const bUnitCollection *usys_iter;
int system_iter;
for (system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
@@ -730,9 +733,9 @@ bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sc
/* 45µm --> 45um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit;
+ const bUnitDef *unit;
/* find and substitute all units */
for (unit = usys->units; unit->name; unit++) {
@@ -769,8 +772,8 @@ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int syste
double bUnit_ClosestScalar(double value, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitDef *unit;
if (usys == NULL)
return -1;
@@ -784,7 +787,7 @@ double bUnit_ClosestScalar(double value, int system, int type)
double bUnit_BaseScalar(int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
return unit_default(usys)->scalar;
}
@@ -794,34 +797,34 @@ bool bUnit_IsValid(int system, int type)
return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
}
-void bUnit_GetSystem(void **usys_pt, int *len, int system, int type)
+void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len)
{
- bUnitCollection *usys = unit_get_system(system, type);
- *usys_pt = usys;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ *r_usys_pt = usys;
if (usys == NULL) {
- *len = 0;
+ *r_len = 0;
return;
}
- *len = usys->length;
+ *r_len = usys->length;
}
-int bUnit_GetBaseUnit(void *usys_pt)
+int bUnit_GetBaseUnit(const void *usys_pt)
{
return ((bUnitCollection *)usys_pt)->base_unit;
}
-const char *bUnit_GetName(void *usys_pt, int index)
+const char *bUnit_GetName(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name;
}
-const char *bUnit_GetNameDisplay(void *usys_pt, int index)
+const char *bUnit_GetNameDisplay(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name_display;
}
-double bUnit_GetScaler(void *usys_pt, int index)
+double bUnit_GetScaler(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].scalar;
}
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index c5359d56f9c..5ef8421c003 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -64,4 +64,16 @@ void _bli_array_binary_or(
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+bool _bli_array_iter_span(
+ const void *arr,
+ unsigned int arr_len, size_t arr_stride,
+ bool use_wrap, bool use_delimit_bounds,
+ bool (*test_fn)(const void *arr_item, void *user_data), void *user_data,
+ unsigned int span_step[2], unsigned int *r_span_len);
+#define BLI_array_iter_span(arr, arr_len, use_wrap, use_delimit_bounds, test_fn, user_data, \
+ span_step, r_span_len) \
+ _bli_array_iter_span( \
+ arr, arr_len, sizeof(*(arr)), use_wrap, use_delimit_bounds, test_fn, user_data, \
+ span_step, r_span_len)
+
#endif /* __BLI_ARRAY_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index be792669ef1..fb8c2520e67 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -132,7 +132,9 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot,
BVHTree_OverlapCallback callback, void *userdata);
-float BLI_bvhtree_getepsilon(const BVHTree *tree);
+int BLI_bvhtree_get_size(const BVHTree *tree);
+
+float BLI_bvhtree_get_epsilon(const BVHTree *tree);
/* find nearest node to the given coordinates
* (if nearest is given it will only search nodes where square distance is smaller than nearest->dist) */
@@ -152,12 +154,12 @@ int BLI_bvhtree_ray_cast(
BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit,
BVHTree_RayCastCallback callback, void *userdata);
-int BLI_bvhtree_ray_cast_all_ex(
- BVHTree *tree, const float co[3], const float dir[3], float radius,
+void BLI_bvhtree_ray_cast_all_ex(
+ BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist,
BVHTree_RayCastCallback callback, void *userdata,
int flag);
-int BLI_bvhtree_ray_cast_all(
- BVHTree *tree, const float co[3], const float dir[3], float radius,
+void BLI_bvhtree_ray_cast_all(
+ BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist,
BVHTree_RayCastCallback callback, void *userdata);
float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3]);
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 20b76354f58..e97a250cd24 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -37,10 +37,6 @@
#include <math.h>
#include "BLI_math_inline.h"
-#ifdef __sun__
-#include <ieeefp.h> /* for finite() */
-#endif
-
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
@@ -146,12 +142,6 @@ static const int NAN_INT = 0x7FC00000;
#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */
-#ifdef WIN32
-# if defined(_MSC_VER)
-# define finite(n) _finite(n)
-# endif
-#endif
-
#if BLI_MATH_DO_INLINE
#include "intern/math_base_inline.c"
#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 7836f12a03e..45edaca544d 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -127,6 +127,12 @@ void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt
/* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]);
+float ray_point_factor_v3_ex(
+ const float p[3], const float ray_origin[3], const float ray_direction[3],
+ const float epsilon, const float fallback);
+float ray_point_factor_v3(
+ const float p[3], const float ray_origin[3], const float ray_direction[3]);
+
float line_point_factor_v3_ex(
const float p[3], const float l1[3], const float l2[3],
const float epsilon, const float fallback);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 6fb983a622e..6d6fbe4e7af 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -246,6 +246,9 @@ bool is_negative_m4(float mat[4][4]);
bool is_zero_m3(float mat[3][3]);
bool is_zero_m4(float mat[4][4]);
+bool equals_m3m3(float mat1[3][3], float mat2[3][3]);
+bool equals_m4m4(float mat1[4][4], float mat2[4][4]);
+
/* SpaceTransform helper */
typedef struct SpaceTransform {
float local2target[4][4];
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index c51446d6cc8..5f76b79b298 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -237,9 +237,9 @@ MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_one_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -272,6 +272,7 @@ float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
+float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 63a07957336..967e0be6d0a 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -21,6 +21,9 @@
#ifndef __BLI_TASK_H__
#define __BLI_TASK_H__
+struct Link;
+struct ListBase;
+
/** \file BLI_task.h
* \ingroup bli
*/
@@ -84,7 +87,9 @@ void BLI_task_pool_push_ex(
TaskPool *pool, TaskRunFunction run, void *taskdata,
bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority);
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run,
- void *taskdata, bool free_taskdata, TaskPriority priority);
+ void *taskdata, bool free_taskdata, TaskPriority priority);
+void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
+ void *taskdata, bool free_taskdata, TaskPriority priority, int thread_id);
/* work and wait until all tasks are done */
void BLI_task_pool_work_and_wait(TaskPool *pool);
@@ -114,11 +119,13 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool);
/* Parallel for routines */
typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
typedef void (*TaskParallelRangeFuncEx)(void *userdata, void *userdata_chunk, const int iter, const int thread_id);
+typedef void (*TaskParallelRangeFuncFinalize)(void *userdata, void *userdata_chunk);
void BLI_task_parallel_range_ex(
int start, int stop,
void *userdata,
void *userdata_chunk,
- const size_t userdata_chunk_size, TaskParallelRangeFuncEx func_ex,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
const bool use_threading,
const bool use_dynamic_scheduling);
void BLI_task_parallel_range(
@@ -127,6 +134,25 @@ void BLI_task_parallel_range(
TaskParallelRangeFunc func,
const bool use_threading);
+void BLI_task_parallel_range_finalize(
+ int start, int stop,
+ void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
+ const bool use_threading,
+ const bool use_dynamic_scheduling);
+
+typedef void (*TaskParallelListbaseFunc)(void *userdata,
+ struct Link *iter,
+ int index);
+void BLI_task_parallel_listbase(
+ struct ListBase *listbase,
+ void *userdata,
+ TaskParallelListbaseFunc func,
+ const bool use_threading);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index bba3fdb37bc..6cef1924e33 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1114,8 +1114,16 @@ void BLI_bvhtree_update_tree(BVHTree *tree)
for (; index >= root; index--)
node_join(tree, *index);
}
+/**
+ * Number of times #BLI_bvhtree_insert has been called.
+ * mainly useful for asserts functions to check we added the correct number.
+ */
+int BLI_bvhtree_get_size(const BVHTree *tree)
+{
+ return tree->totleaf;
+}
-float BLI_bvhtree_getepsilon(const BVHTree *tree)
+float BLI_bvhtree_get_epsilon(const BVHTree *tree)
{
return tree->epsilon;
}
@@ -1565,7 +1573,7 @@ int BLI_bvhtree_find_nearest(
/* Determines the distance that the ray must travel to hit the bounding volume of the given node */
-static float ray_nearest_hit(BVHRayCastData *data, const float bv[6])
+static float ray_nearest_hit(const BVHRayCastData *data, const float bv[6])
{
int i;
@@ -1635,7 +1643,9 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
* before calling the ray-primitive functions */
/* XXX: temporary solution for particles until fast_ray_nearest_hit supports ray.radius */
float dist = (data->ray.radius == 0.0f) ? fast_ray_nearest_hit(data, node) : ray_nearest_hit(data, node->bv);
- if (dist >= data->hit.dist) return;
+ if (dist >= data->hit.dist) {
+ return;
+ }
if (node->totnode == 0) {
if (data->callback) {
@@ -1662,6 +1672,9 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
}
}
+/**
+ * A version of #dfs_raycast with minor changes to reset the index & dist each ray cast.
+ */
static void dfs_raycast_all(BVHRayCastData *data, BVHNode *node)
{
int i;
@@ -1670,18 +1683,16 @@ static void dfs_raycast_all(BVHRayCastData *data, BVHNode *node)
* before calling the ray-primitive functions */
/* XXX: temporary solution for particles until fast_ray_nearest_hit supports ray.radius */
float dist = (data->ray.radius == 0.0f) ? fast_ray_nearest_hit(data, node) : ray_nearest_hit(data, node->bv);
+ if (dist >= data->hit.dist) {
+ return;
+ }
if (node->totnode == 0) {
- if (data->callback) {
- data->hit.index = -1;
- data->hit.dist = BVH_RAYCAST_DIST_MAX;
- data->callback(data->userdata, node->index, &data->ray, &data->hit);
- }
- else {
- data->hit.index = node->index;
- data->hit.dist = dist;
- madd_v3_v3v3fl(data->hit.co, data->ray.origin, data->ray.direction, dist);
- }
+ /* no need to check for 'data->callback' (using 'all' only makes sense with a callback). */
+ dist = data->hit.dist;
+ data->callback(data->userdata, node->index, &data->ray, &data->hit);
+ data->hit.index = -1;
+ data->hit.dist = dist;
}
else {
/* pick loop direction to dive into the tree (based on ray direction and split axis) */
@@ -1832,9 +1843,14 @@ float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], cons
/**
* Calls the callback for every ray intersection
+ *
+ * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
+ * however using this function means existing generic callbacks can be used from custom callbacks without
+ * having to handle resetting the hit beforehand.
+ * It also avoid redundant argument and return value which aren't meaningful when collecting multiple hits.
*/
-int BLI_bvhtree_ray_cast_all_ex(
- BVHTree *tree, const float co[3], const float dir[3], float radius,
+void BLI_bvhtree_ray_cast_all_ex(
+ BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist,
BVHTree_RayCastCallback callback, void *userdata,
int flag)
{
@@ -1842,6 +1858,7 @@ int BLI_bvhtree_ray_cast_all_ex(
BVHNode *root = tree->nodes[tree->totleaf];
BLI_ASSERT_UNIT_V3(dir);
+ BLI_assert(callback != NULL);
data.tree = tree;
@@ -1855,20 +1872,18 @@ int BLI_bvhtree_ray_cast_all_ex(
bvhtree_ray_cast_data_precalc(&data, flag);
data.hit.index = -1;
- data.hit.dist = BVH_RAYCAST_DIST_MAX;
+ data.hit.dist = hit_dist;
if (root) {
dfs_raycast_all(&data, root);
}
-
- return data.hit.index;
}
-int BLI_bvhtree_ray_cast_all(
- BVHTree *tree, const float co[3], const float dir[3], float radius,
+void BLI_bvhtree_ray_cast_all(
+ BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist,
BVHTree_RayCastCallback callback, void *userdata)
{
- return BLI_bvhtree_ray_cast_all_ex(tree, co, dir, radius, callback, userdata, BVH_RAYCAST_DEFAULT);
+ BLI_bvhtree_ray_cast_all_ex(tree, co, dir, radius, hit_dist, callback, userdata, BVH_RAYCAST_DEFAULT);
}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 52ca835876e..5d485e2033d 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -169,4 +169,128 @@ void _bli_array_binary_or(
while (i--) {
*(dst++) = *(src_a++) | *(src_b++);
}
-} \ No newline at end of file
+}
+
+/**
+ * Utility function to iterate over contiguous items in an array.
+ *
+ * \param use_wrap: Detect contiguous ranges across the first/last points.
+ * In this case the second index of \a span_step may be lower than the first,
+ * which indicates the values are wrapped.
+ * \param use_delimit_bounds: When false, ranges that defined by the start/end indices are excluded.
+ * This option has no effect when \a use_wrap is enabled.
+ * \param test_fn: Function to test if the item should be included in the range.
+ * \param user_data: User data for \a test_fn.
+ * \param span_step: Indices to iterate over,
+ * initialize both values to the array length to initialize iteration.
+ * \param: r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * where calculating the length isnt a simple subtraction.
+ */
+bool _bli_array_iter_span(
+ const void *arr,
+ unsigned int arr_len, size_t arr_stride,
+ bool use_wrap, bool use_delimit_bounds,
+ bool (*test_fn)(const void *arr_item, void *user_data), void *user_data,
+ unsigned int span_step[2], unsigned int *r_span_len)
+{
+ if (arr_len == 0) {
+ return false;
+ }
+ else if (use_wrap && (span_step[0] != arr_len) && (span_step[0] > span_step[1])) {
+ return false;
+ }
+
+ const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const void *item_prev;
+ bool test_prev;
+
+ unsigned int i_curr;
+
+ if ((span_step[0] == arr_len) && (span_step[1] == arr_len)) {
+ if (use_wrap) {
+ item_prev = POINTER_OFFSET(arr, (arr_len - 1) * arr_stride_uint);
+ i_curr = 0;
+ test_prev = test_fn(item_prev, user_data);
+ }
+ else if (use_delimit_bounds == false) {
+ item_prev = arr;
+ i_curr = 1;
+ test_prev = test_fn(item_prev, user_data);
+ }
+ else {
+ item_prev = NULL;
+ i_curr = 0;
+ test_prev = false;
+ }
+ }
+ else if ((i_curr = span_step[1] + 2) < arr_len) {
+ item_prev = POINTER_OFFSET(arr, (span_step[1] + 1) * arr_stride_uint);
+ test_prev = test_fn(item_prev, user_data);
+ }
+ else {
+ return false;
+ }
+ BLI_assert(i_curr < arr_len);
+
+ const void *item_curr = POINTER_OFFSET(arr, i_curr * arr_stride_uint);
+
+ while (i_curr < arr_len) {
+ bool test_curr = test_fn(item_curr, user_data);
+ if ((test_prev == false) &&
+ (test_curr == true))
+ {
+ unsigned int span_len;
+ unsigned int i_step_prev = i_curr;
+
+ if (use_wrap) {
+ unsigned int i_step = i_curr + 1;
+ if (UNLIKELY(i_step == arr_len)) {
+ i_step = 0;
+ }
+ while (test_fn(POINTER_OFFSET(arr, i_step * arr_stride_uint), user_data)) {
+ i_step_prev = i_step;
+ i_step++;
+ if (UNLIKELY(i_step == arr_len)) {
+ i_step = 0;
+ }
+ }
+
+ if (i_step_prev < i_curr) {
+ span_len = (i_step_prev + (arr_len - i_curr)) + 1;
+ }
+ else {
+ span_len = (i_step_prev - i_curr) + 1;
+ }
+ }
+ else {
+ unsigned int i_step = i_curr + 1;
+ while ((i_step != arr_len) &&
+ test_fn(POINTER_OFFSET(arr, i_step * arr_stride_uint), user_data))
+ {
+ i_step_prev = i_step;
+ i_step++;
+ }
+
+ span_len = (i_step_prev - i_curr) + 1;
+
+ if ((use_delimit_bounds == false) && (i_step_prev == arr_len - 1)) {
+ return false;
+ }
+ }
+
+ span_step[0] = i_curr;
+ span_step[1] = i_step_prev;
+ *r_span_len = span_len;
+
+ return true;
+ }
+
+ test_prev = test_curr;
+
+ item_prev = item_curr;
+ item_curr = POINTER_OFFSET(item_curr, arr_stride_uint);
+ i_curr++;
+ }
+
+ return false;
+}
diff --git a/source/blender/blenlib/intern/graph.c b/source/blender/blenlib/intern/graph.c
index 81cc9fde01f..911e8aae340 100644
--- a/source/blender/blenlib/intern/graph.c
+++ b/source/blender/blenlib/intern/graph.c
@@ -578,7 +578,7 @@ static void handleRadialSymmetry(BGraph *graph, BNode *root_node, int depth, flo
unit = ring;
/* fill in the ring */
- for (unit = ring, i = 0; i < root_node->degree; i++) {
+ for (i = 0; i < root_node->degree; i++) {
BArc *connectedArc = root_node->arcs[i];
/* depth is store as a negative in flag. symmetry level is positive */
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 0a1e9e8a8a1..14eba3e61a4 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -56,7 +56,7 @@ double double_round(double x, int ndigits)
pow2 = 1.0;
y = (x * pow1) * pow2;
/* if y overflows, then rounded value is exactly x */
- if (!finite(y))
+ if (!isfinite(y))
return x;
}
else {
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index f70c12bd26e..8d2d80c2a35 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -33,7 +33,10 @@
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
+
+#ifdef __SSE2__
+# include <emmintrin.h>
+#endif
#include "BLI_math_base.h"
@@ -311,4 +314,98 @@ MINLINE int signum_i(float a)
else return 0;
}
+/* Internal helpers for SSE2 implementation.
+ *
+ * NOTE: Are to be called ONLY from inside `#ifdef __SSE2__` !!!
+ */
+
+#ifdef __SSE2__
+
+/* Calculate initial guess for arg^exp based on float representation
+ * This method gives a constant bias, which can be easily compensated by
+ * multiplicating with bias_coeff.
+ * Gives better results for exponents near 1 (e. g. 4/5).
+ * exp = exponent, encoded as uint32_t
+ * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as
+ * uint32_t
+ *
+ * We hope that exp and e2coeff gets properly inlined
+ */
+MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp,
+ const int e2coeff,
+ const __m128 arg)
+{
+ __m128 ret;
+ ret = _mm_mul_ps(arg, _mm_castsi128_ps(_mm_set1_epi32(e2coeff)));
+ ret = _mm_cvtepi32_ps(_mm_castps_si128(ret));
+ ret = _mm_mul_ps(ret, _mm_castsi128_ps(_mm_set1_epi32(exp)));
+ ret = _mm_castsi128_ps(_mm_cvtps_epi32(ret));
+ return ret;
+}
+
+/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
+MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(
+ const __m128 old_result,
+ const __m128 x)
+{
+ __m128 approx2 = _mm_mul_ps(old_result, old_result);
+ __m128 approx4 = _mm_mul_ps(approx2, approx2);
+ __m128 t = _mm_div_ps(x, approx4);
+ __m128 summ = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(4.0f), old_result), t); /* fma */
+ return _mm_mul_ps(summ, _mm_set1_ps(1.0f / 5.0f));
+}
+
+/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
+MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
+{
+ /* max, avg and |avg| errors were calculated in gcc without FMA instructions
+ * The final precision should be better than powf in glibc */
+
+ /* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize
+ * avg error.
+ */
+ /* 0x3F4CCCCD = 4/5 */
+ /* 0x4F55A7FB = 2^(127/(4/5) - 127) * 0.994^(1/(4/5)) */
+ /* error max = 0.17 avg = 0.0018 |avg| = 0.05 */
+ __m128 x = _bli_math_fastpow(0x3F4CCCCD, 0x4F55A7FB, arg);
+ __m128 arg2 = _mm_mul_ps(arg, arg);
+ __m128 arg4 = _mm_mul_ps(arg2, arg2);
+ /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
+ x = _bli_math_improve_5throot_solution(x, arg4);
+ /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
+ x = _bli_math_improve_5throot_solution(x, arg4);
+ /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
+ x = _bli_math_improve_5throot_solution(x, arg4);
+ return _mm_mul_ps(x, _mm_mul_ps(x, x));
+}
+
+/* Calculate powf(x, 1.0f / 2.4) */
+MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
+{
+ /* 5/12 is too small, so compute the 4th root of 20/12 instead.
+ * 20/12 = 5/3 = 1 + 2/3 = 2 - 1/3. 2/3 is a suitable argument for fastpow.
+ * weighting coefficient: a^-1/2 = 2 a; a = 2^-2/3
+ */
+ __m128 xf = _bli_math_fastpow(0x3f2aaaab, 0x5eb504f3, arg);
+ __m128 xover = _mm_mul_ps(arg, xf);
+ __m128 xfm1 = _mm_rsqrt_ps(xf);
+ __m128 x2 = _mm_mul_ps(arg, arg);
+ __m128 xunder = _mm_mul_ps(x2, xfm1);
+ /* sqrt2 * over + 2 * sqrt2 * under */
+ __m128 xavg = _mm_mul_ps(_mm_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f),
+ _mm_add_ps(xover, xunder));
+ xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+ xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+ return xavg;
+}
+
+MALWAYS_INLINE __m128 _bli_math_blend_sse(const __m128 mask,
+ const __m128 a,
+ const __m128 b)
+{
+ return _mm_or_ps(_mm_and_ps(mask, a), _mm_andnot_ps(mask, b));
+}
+
+#endif /* __SSE2__ */
+
#endif /* __MATH_BASE_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 45466226e72..180d62105c4 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -28,6 +28,7 @@
*/
+#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
@@ -38,6 +39,52 @@
/******************************** Color Space ********************************/
+#ifdef __SSE2__
+
+MALWAYS_INLINE __m128 srgb_to_linearrgb_v4_simd(const __m128 c)
+{
+ __m128 cmp = _mm_cmplt_ps(c, _mm_set1_ps(0.04045f));
+ __m128 lt = _mm_max_ps(_mm_mul_ps(c, _mm_set1_ps(1.0f / 12.92f)),
+ _mm_set1_ps(0.0f));
+ __m128 gtebase = _mm_mul_ps(_mm_add_ps(c, _mm_set1_ps(0.055f)),
+ _mm_set1_ps(1.0f / 1.055f)); /* fma */
+ __m128 gte = _bli_math_fastpow24(gtebase);
+ return _bli_math_blend_sse(cmp, lt, gte);
+}
+
+MALWAYS_INLINE __m128 linearrgb_to_srgb_v4_simd(const __m128 c)
+{
+ __m128 cmp = _mm_cmplt_ps(c, _mm_set1_ps(0.0031308f));
+ __m128 lt = _mm_max_ps(_mm_mul_ps(c, _mm_set1_ps(12.92f)),
+ _mm_set1_ps(0.0f));
+ __m128 gte = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.055f),
+ _bli_math_fastpow512(c)),
+ _mm_set1_ps(-0.055f));
+ return _bli_math_blend_sse(cmp, lt, gte);
+}
+
+MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
+{
+ float r[4] = {srgb[0], srgb[1], srgb[2], 0.0f};
+ __m128 *rv = (__m128 *)&r;
+ *rv = srgb_to_linearrgb_v4_simd(*rv);
+ linear[0] = r[0];
+ linear[1] = r[1];
+ linear[2] = r[2];
+}
+
+MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
+{
+ float r[4] = {linear[0], linear[1], linear[2], 0.0f};
+ __m128 *rv = (__m128 *)&r;
+ *rv = linearrgb_to_srgb_v4_simd(*rv);
+ srgb[0] = r[0];
+ srgb[1] = r[1];
+ srgb[2] = r[2];
+}
+
+#else /* __SSE2__ */
+
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
{
linear[0] = srgb_to_linearrgb(srgb[0]);
@@ -51,6 +98,7 @@ MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
srgb[1] = linearrgb_to_srgb(linear[1]);
srgb[2] = linearrgb_to_srgb(linear[2]);
}
+#endif /* __SSE2__ */
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
{
@@ -98,10 +146,14 @@ MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]
inv_alpha = 1.0f / alpha;
}
- linear[0] = srgb_to_linearrgb(srgb[0] * inv_alpha) * alpha;
- linear[1] = srgb_to_linearrgb(srgb[1] * inv_alpha) * alpha;
- linear[2] = srgb_to_linearrgb(srgb[2] * inv_alpha) * alpha;
+ linear[0] = srgb[0] * inv_alpha;
+ linear[1] = srgb[1] * inv_alpha;
+ linear[2] = srgb[2] * inv_alpha;
linear[3] = srgb[3];
+ srgb_to_linearrgb_v3_v3(linear, linear);
+ linear[0] *= alpha;
+ linear[1] *= alpha;
+ linear[2] *= alpha;
}
MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4])
@@ -117,10 +169,14 @@ MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]
inv_alpha = 1.0f / alpha;
}
- srgb[0] = linearrgb_to_srgb(linear[0] * inv_alpha) * alpha;
- srgb[1] = linearrgb_to_srgb(linear[1] * inv_alpha) * alpha;
- srgb[2] = linearrgb_to_srgb(linear[2] * inv_alpha) * alpha;
+ srgb[0] = linear[0] * inv_alpha;
+ srgb[1] = linear[1] * inv_alpha;
+ srgb[2] = linear[2] * inv_alpha;
srgb[3] = linear[3];
+ linearrgb_to_srgb_v3_v3(srgb, srgb);
+ srgb[0] *= alpha;
+ srgb[1] *= alpha;
+ srgb[2] *= alpha;
}
/* LUT accelerated conversions */
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 482709e572f..f80099bee1b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2506,6 +2506,22 @@ float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2],
return lambda;
}
+float ray_point_factor_v3_ex(
+ const float p[3], const float ray_origin[3], const float ray_direction[3],
+ const float epsilon, const float fallback)
+{
+ float p_relative[3];
+ sub_v3_v3v3(p_relative, p, ray_origin);
+ const float dot = len_squared_v3(ray_direction);
+ return (dot > epsilon) ? (dot_v3v3(ray_direction, p_relative) / dot) : fallback;
+}
+
+float ray_point_factor_v3(
+ const float p[3], const float ray_origin[3], const float ray_direction[3])
+{
+ return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
+}
+
/**
* A simplified version of #closest_to_line_v3
* we only need to return the ``lambda``
@@ -2525,8 +2541,8 @@ float line_point_factor_v3_ex(
return (dot_v3v3(u, h) / dot_v3v3(u, u));
#else
/* better check for zero */
- dot = dot_v3v3(u, u);
- return (fabsf(dot) > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
+ dot = len_squared_v3(u);
+ return (dot > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
#endif
}
float line_point_factor_v3(
@@ -2547,8 +2563,8 @@ float line_point_factor_v2_ex(
return (dot_v2v2(u, h) / dot_v2v2(u, u));
#else
/* better check for zero */
- dot = dot_v2v2(u, u);
- return (fabsf(dot) > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
+ dot = len_squared_v2(u);
+ return (dot > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
#endif
}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 52ff6fd3e8a..0e3f905ef16 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1828,6 +1828,21 @@ bool is_zero_m4(float mat[4][4])
is_zero_v4(mat[3]));
}
+bool equals_m3m3(float mat1[3][3], float mat2[3][3])
+{
+ return (equals_v3v3(mat1[0], mat2[0]) &&
+ equals_v3v3(mat1[1], mat2[1]) &&
+ equals_v3v3(mat1[2], mat2[2]));
+}
+
+bool equals_m4m4(float mat1[4][4], float mat2[4][4])
+{
+ return (equals_v4v4(mat1[0], mat2[0]) &&
+ equals_v4v4(mat1[1], mat2[1]) &&
+ equals_v4v4(mat1[2], mat2[2]) &&
+ equals_v4v4(mat1[3], mat2[3]));
+}
+
/* make a 4x4 matrix out of 3 transform components */
/* matrices are made in the order: scale * rot * loc */
/* TODO: need to have a version that allows for rotation order... */
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 8d33e04241a..7f2db3743df 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -336,6 +336,25 @@ void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2])
v[1] = v1[1] + (v1[1] - v2[1]);
}
+
+/********************************* Comparison ********************************/
+
+bool is_finite_v2(const float v[2])
+{
+ return (isfinite(v[0]) && isfinite(v[1]));
+}
+
+bool is_finite_v3(const float v[3])
+{
+ return (isfinite(v[0]) && isfinite(v[1]) && isfinite(v[2]));
+}
+
+bool is_finite_v4(const float v[4])
+{
+ return (isfinite(v[0]) && isfinite(v[1]) && isfinite(v[2]) && isfinite(v[3]));
+}
+
+
/********************************** Angles ***********************************/
/* Return the angle in radians between vecs 1-2 and 2-3 in radians
@@ -397,6 +416,19 @@ float angle_v2v2v2(const float v1[2], const float v2[2], const float v3[2])
return angle_normalized_v2v2(vec1, vec2);
}
+/* Quicker than full angle computation */
+float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
+{
+ float vec1[2], vec2[2];
+
+ sub_v2_v2v2(vec1, p2, p1);
+ sub_v2_v2v2(vec2, p2, p3);
+ normalize_v2(vec1);
+ normalize_v2(vec2);
+
+ return dot_v2v2(vec1, vec2);
+}
+
/* Return the shortest angle in radians between the 2 vectors */
float angle_v2v2(const float v1[2], const float v2[2])
{
@@ -578,19 +610,28 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
* Projecting will make \a c a copy of \a v orthogonal to \a v_plane.
*
* \note If \a v is exactly perpendicular to \a v_plane, \a c will just be a copy of \a v.
+ *
+ * \note This function is a convenience to call:
+ * \code{.c}
+ * project_v3_v3v3(c, v, v_plane);
+ * sub_v3_v3v3(c, v, c);
+ * \endcode
*/
void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3])
{
- float delta[3];
- project_v3_v3v3(delta, v, v_plane);
- sub_v3_v3v3(c, v, delta);
+ const float mul = dot_v3v3(v, v_plane) / dot_v3v3(v_plane, v_plane);
+
+ c[0] = v[0] - (mul * v_plane[0]);
+ c[1] = v[1] - (mul * v_plane[1]);
+ c[2] = v[2] - (mul * v_plane[2]);
}
void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2])
{
- float delta[2];
- project_v2_v2v2(delta, v, v_plane);
- sub_v2_v2v2(c, v, delta);
+ const float mul = dot_v2v2(v, v_plane) / dot_v2v2(v_plane, v_plane);
+
+ c[0] = v[0] - (mul * v_plane[0]);
+ c[1] = v[1] - (mul * v_plane[1]);
}
/* project a vector on a plane defined by normal and a plane point p */
@@ -647,7 +688,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
if (f > eps) {
const float d = 1.0f / sqrtf(f);
- BLI_assert(finite(d));
+ BLI_assert(isfinite(d));
r_n1[0] = n[1] * d;
r_n1[1] = -n[0] * d;
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 17e2da3f1cb..b43fb6e986c 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -952,21 +952,6 @@ MINLINE bool is_zero_v4(const float v[4])
return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f);
}
-MINLINE bool is_finite_v2(const float v[2])
-{
- return (finite(v[0]) && finite(v[1]));
-}
-
-MINLINE bool is_finite_v3(const float v[3])
-{
- return (finite(v[0]) && finite(v[1]) && finite(v[2]));
-}
-
-MINLINE bool is_finite_v4(const float v[4])
-{
- return (finite(v[0]) && finite(v[1]) && finite(v[2]) && finite(v[3]));
-}
-
MINLINE bool is_one_v3(const float v[3])
{
return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f);
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index fadfb64f1e1..2b793841c38 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1927,8 +1927,7 @@ const char *BLI_first_slash(const char *string)
if (!ffslash) return fbslash;
else if (!fbslash) return ffslash;
- if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash;
- else return fbslash;
+ return (ffslash < fbslash) ? ffslash : fbslash;
}
/**
@@ -1942,8 +1941,7 @@ const char *BLI_last_slash(const char *string)
if (!lfslash) return lbslash;
else if (!lbslash) return lfslash;
- if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash;
- else return lfslash;
+ return (lfslash > lbslash) ? lfslash : lbslash;
}
/**
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 800f4cb23c3..8d9881e4539 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -768,11 +768,7 @@ static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
}
/**
- * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
- *
- * \param coords pairs describing vertices of the polygon, in either clockwise or counterclockwise order.
- * \return triples of triangle indices in clockwise order.
- * Note the returned array is reused for later calls to the same method.
+ * Initializes the #PolyFill structure before tessellating with #polyfill_calc.
*/
static void polyfill_prepare(
PolyFill *pf,
@@ -862,6 +858,9 @@ static void polyfill_calc(
pf_triangulate(pf);
}
+/**
+ * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
+ */
void BLI_polyfill_calc_arena(
const float (*coords)[2],
const unsigned int coords_tot,
@@ -905,6 +904,19 @@ void BLI_polyfill_calc_arena(
#endif
}
+/**
+ * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
+ *
+ * \param coords: 2D coordinates describing vertices of the polygon,
+ * in either clockwise or counterclockwise order.
+ * \param coords_tot: Total points in the array.
+ * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
+ *
+ * \param r_tris: This array is filled in with triangle indices in clockwise order.
+ * The length of the array must be ``coords_tot - 2``.
+ * Indices are guaranteed to be assigned to unique triangles, with valid indices,
+ * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
+ */
void BLI_polyfill_calc(
const float (*coords)[2],
const unsigned int coords_tot,
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 8a96daeeb91..4406a45d4fc 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -28,6 +28,15 @@
/** \file blender/blenlib/intern/scanfill.c
* \ingroup bli
+ *
+ * Triangulate multiple 2D/3D polygon with support for holes,
+ * use for tessellating curves, fonts and geometry.
+ * See main function #BLI_scanfill_calc
+ *
+ * Uses sweep-line method.
+ *
+ * \note There is a similar API in polyfill2d.c
+ * which uses ear clipping, but has no hole support.
*/
#include <stdio.h>
@@ -602,7 +611,7 @@ static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int fl
else {
/* test rest of vertices */
ScanFillVertLink *best_sc = NULL;
- float best_angle = 3.14f;
+ float angle_best_cos = -1.0f;
float miny;
bool firsttime = false;
@@ -633,21 +642,18 @@ static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int fl
best_sc = sc1;
}
else {
- float angle;
-
/* prevent angle calc for the simple cases only 1 vertex is found */
if (firsttime == false) {
- best_angle = angle_v2v2v2(v2->xy, v1->xy, best_sc->vert->xy);
+ angle_best_cos = cos_v2v2v2(v2->xy, v1->xy, best_sc->vert->xy);
firsttime = true;
}
- angle = angle_v2v2v2(v2->xy, v1->xy, sc1->vert->xy);
- if (angle < best_angle) {
+ const float angle_test_cos = cos_v2v2v2(v2->xy, v1->xy, sc1->vert->xy);
+ if (angle_test_cos > angle_best_cos) {
best_sc = sc1;
- best_angle = angle;
+ angle_best_cos = angle_test_cos;
}
}
-
}
}
}
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index e7938b750da..4ef42dcce6f 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -28,6 +28,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -35,8 +37,17 @@
#include "atomic_ops.h"
+/* Define this to enable some detailed statistic print. */
+#undef DEBUG_STATS
+
/* Types */
+/* Number of per-thread pre-allocated tasks.
+ *
+ * For more details see description of TaskMemPool.
+ */
+#define MEMPOOL_SIZE 256
+
typedef struct Task {
struct Task *next, *prev;
@@ -47,6 +58,50 @@ typedef struct Task {
TaskPool *pool;
} Task;
+/* This is a per-thread storage of pre-allocated tasks.
+ *
+ * The idea behind this is simple: reduce amount of malloc() calls when pushing
+ * new task to the pool. This is done by keeping memory from the tasks which
+ * were finished already, so instead of freeing that memory we put it to the
+ * pool for the later re-use.
+ *
+ * The tricky part here is to avoid any inter-thread synchronization, hence no
+ * lock must exist around this pool. The pool will become an owner of the pointer
+ * from freed task, and only corresponding thread will be able to use this pool
+ * (no memory stealing and such).
+ *
+ * This leads to the following use of the pool:
+ *
+ * - task_push() should provide proper thread ID from which the task is being
+ * pushed from.
+ *
+ * - Task allocation function which check corresponding memory pool and if there
+ * is any memory in there it'll mark memory as re-used, remove it from the pool
+ * and use that memory for the new task.
+ *
+ * At this moment task queue owns the memory.
+ *
+ * - When task is done and task_free() is called the memory will be put to the
+ * pool which corresponds to a thread which handled the task.
+ */
+typedef struct TaskMemPool {
+ /* Number of pre-allocated tasks in the pool. */
+ int num_tasks;
+ /* Pre-allocated task memory pointers. */
+ Task *tasks[MEMPOOL_SIZE];
+} TaskMemPool;
+
+#ifdef DEBUG_STATS
+typedef struct TaskMemPoolStats {
+ /* Number of allocations. */
+ int num_alloc;
+ /* Number of avoided allocations (pointer was re-used from the pool). */
+ int num_reuse;
+ /* Number of discarded memory due to pool saturation, */
+ int num_discard;
+} TaskMemPoolStats;
+#endif
+
struct TaskPool {
TaskScheduler *scheduler;
@@ -62,14 +117,32 @@ struct TaskPool {
volatile bool do_cancel;
- /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler has to use its special
- * background fallback thread in case we are in single-threaded situation. */
+ /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler
+ * has to use its special background fallback thread in case we are in
+ * single-threaded situation.
+ */
bool run_in_background;
+
+ /* This pool is used for caching task pointers for thread id 0.
+ * This could either point to a global scheduler's task_mempool[0] if the
+ * pool is handled form the main thread or point to task_mempool_local
+ * otherwise.
+ *
+ * This way we solve possible threading conflicts accessing same global
+ * memory pool from multiple threads from which wait_work() is called.
+ */
+ TaskMemPool *task_mempool;
+ TaskMemPool task_mempool_local;
+
+#ifdef DEBUG_STATS
+ TaskMemPoolStats *mempool_stats;
+#endif
};
struct TaskScheduler {
pthread_t *threads;
struct TaskThread *task_threads;
+ TaskMemPool *task_mempool;
int num_threads;
bool background_thread_only;
@@ -98,6 +171,63 @@ static void task_data_free(Task *task, const int thread_id)
}
}
+BLI_INLINE TaskMemPool *get_task_mempool(TaskPool *pool, const int thread_id)
+{
+ if (thread_id == 0) {
+ return pool->task_mempool;
+ }
+ return &pool->scheduler->task_mempool[thread_id];
+}
+
+static Task *task_alloc(TaskPool *pool, const int thread_id)
+{
+ assert(thread_id <= pool->scheduler->num_threads);
+ if (thread_id != -1) {
+ assert(thread_id >= 0);
+ TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
+ /* Try to re-use task memory from a thread local storage. */
+ if (mem_pool->num_tasks > 0) {
+ --mem_pool->num_tasks;
+ /* Success! We've just avoided task allocation. */
+#ifdef DEBUG_STATS
+ pool->mempool_stats[thread_id].num_reuse++;
+#endif
+ return mem_pool->tasks[mem_pool->num_tasks];
+ }
+ /* We are doomed to allocate new task data. */
+#ifdef DEBUG_STATS
+ pool->mempool_stats[thread_id].num_alloc++;
+#endif
+ }
+ return MEM_mallocN(sizeof(Task), "New task");
+}
+
+static void task_free(TaskPool *pool, Task *task, const int thread_id)
+{
+ task_data_free(task, thread_id);
+ assert(thread_id >= 0);
+ assert(thread_id <= pool->scheduler->num_threads);
+ TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
+ if (mem_pool->num_tasks < MEMPOOL_SIZE - 1) {
+ /* Successfully allowed the task to be re-used later. */
+ mem_pool->tasks[mem_pool->num_tasks] = task;
+ ++mem_pool->num_tasks;
+ }
+ else {
+ /* Local storage saturated, no other way than just discard
+ * the memory.
+ *
+ * TODO(sergey): We can perhaps store such pointer in a global
+ * scheduler pool, maybe it'll be faster than discarding and
+ * allocating again.
+ */
+ MEM_freeN(task);
+#ifdef DEBUG_STATS
+ pool->mempool_stats[thread_id].num_discard++;
+#endif
+ }
+}
+
/* Task Scheduler */
static void task_pool_num_decrease(TaskPool *pool, size_t done)
@@ -196,8 +326,7 @@ static void *task_scheduler_thread_run(void *thread_p)
task->run(pool, task->taskdata, thread_id);
/* delete task */
- task_data_free(task, thread_id);
- MEM_freeN(task);
+ task_free(pool, task, thread_id);
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
@@ -249,6 +378,9 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
}
}
+
+ scheduler->task_mempool = MEM_callocN(sizeof(*scheduler->task_mempool) * (num_threads + 1),
+ "TaskScheduler task_mempool");
}
return scheduler;
@@ -281,6 +413,16 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
MEM_freeN(scheduler->task_threads);
}
+ /* Delete task memory pool */
+ if (scheduler->task_mempool) {
+ for (int i = 0; i <= scheduler->num_threads; ++i) {
+ for (int j = 0; j < scheduler->task_mempool[i].num_tasks; ++j) {
+ MEM_freeN(scheduler->task_mempool[i].tasks[j]);
+ }
+ }
+ MEM_freeN(scheduler->task_mempool);
+ }
+
/* delete leftover tasks */
for (task = scheduler->queue.first; task; task = task->next) {
task_data_free(task, 0);
@@ -344,7 +486,7 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, const bool is_background)
{
- TaskPool *pool = MEM_callocN(sizeof(TaskPool), "TaskPool");
+ TaskPool *pool = MEM_mallocN(sizeof(TaskPool), "TaskPool");
#ifndef NDEBUG
/* Assert we do not try to create a background pool from some parent task - those only work OK from main thread. */
@@ -360,6 +502,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
pool->scheduler = scheduler;
pool->num = 0;
+ pool->done = 0;
pool->num_threads = 0;
pool->currently_running_tasks = 0;
pool->do_cancel = false;
@@ -371,6 +514,20 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
pool->userdata = userdata;
BLI_mutex_init(&pool->user_mutex);
+ if (BLI_thread_is_main()) {
+ pool->task_mempool = scheduler->task_mempool;
+ }
+ else {
+ pool->task_mempool = &pool->task_mempool_local;
+ pool->task_mempool_local.num_tasks = 0;
+ }
+
+#ifdef DEBUG_STATS
+ pool->mempool_stats =
+ MEM_callocN(sizeof(*pool->mempool_stats) * (scheduler->num_threads + 1),
+ "per-taskpool mempool stats");
+#endif
+
/* Ensure malloc will go fine from threads,
*
* This is needed because we could be in main thread here
@@ -416,16 +573,36 @@ void BLI_task_pool_free(TaskPool *pool)
BLI_mutex_end(&pool->user_mutex);
+ /* Free local memory pool, those pointers are lost forever. */
+ if (pool->task_mempool == &pool->task_mempool_local) {
+ for (int i = 0; i < pool->task_mempool_local.num_tasks; i++) {
+ MEM_freeN(pool->task_mempool_local.tasks[i]);
+ }
+ }
+
+#ifdef DEBUG_STATS
+ printf("Thread ID Allocated Reused Discarded\n");
+ for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) {
+ printf("%02d %05d %05d %05d\n",
+ i,
+ pool->mempool_stats[i].num_alloc,
+ pool->mempool_stats[i].num_reuse,
+ pool->mempool_stats[i].num_discard);
+ }
+ MEM_freeN(pool->mempool_stats);
+#endif
+
MEM_freeN(pool);
BLI_end_threaded_malloc();
}
-void BLI_task_pool_push_ex(
+static void task_pool_push(
TaskPool *pool, TaskRunFunction run, void *taskdata,
- bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority)
+ bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority,
+ int thread_id)
{
- Task *task = MEM_callocN(sizeof(Task), "Task");
+ Task *task = task_alloc(pool, thread_id);
task->run = run;
task->taskdata = taskdata;
@@ -436,12 +613,25 @@ void BLI_task_pool_push_ex(
task_scheduler_push(pool->scheduler, task, priority);
}
+void BLI_task_pool_push_ex(
+ TaskPool *pool, TaskRunFunction run, void *taskdata,
+ bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority)
+{
+ task_pool_push(pool, run, taskdata, free_taskdata, freedata, priority, -1);
+}
+
void BLI_task_pool_push(
TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskPriority priority)
{
BLI_task_pool_push_ex(pool, run, taskdata, free_taskdata, NULL, priority);
}
+void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
+ void *taskdata, bool free_taskdata, TaskPriority priority, int thread_id)
+{
+ task_pool_push(pool, run, taskdata, free_taskdata, NULL, priority, thread_id);
+}
+
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
TaskScheduler *scheduler = pool->scheduler;
@@ -481,8 +671,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
work_task->run(pool, work_task->taskdata, 0);
/* delete task */
- task_data_free(task, 0);
- MEM_freeN(work_task);
+ task_free(pool, task, 0);
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
@@ -563,16 +752,13 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
*
* Main functions:
* - #BLI_task_parallel_range
+ * - #BLI_task_parallel_listbase (#ListBase - double linked list)
*
* TODO:
- * - #BLI_task_parallel_foreach_listbase (#ListBase - double linked list)
* - #BLI_task_parallel_foreach_link (#Link - single linked list)
* - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set)
* - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools)
*
- * Possible improvements:
- *
- * - Chunk iterations to reduce number of spin locks.
*/
/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
@@ -582,53 +768,38 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
typedef struct ParallelRangeState {
int start, stop;
void *userdata;
- void *userdata_chunk;
- size_t userdata_chunk_size;
TaskParallelRangeFunc func;
TaskParallelRangeFuncEx func_ex;
int iter;
int chunk_size;
- SpinLock lock;
} ParallelRangeState;
BLI_INLINE bool parallel_range_next_iter_get(
ParallelRangeState * __restrict state,
int * __restrict iter, int * __restrict count)
{
- bool result = false;
- BLI_spin_lock(&state->lock);
- if (state->iter < state->stop) {
- *count = min_ii(state->chunk_size, state->stop - state->iter);
- *iter = state->iter;
- state->iter += *count;
- result = true;
- }
- BLI_spin_unlock(&state->lock);
- return result;
+ uint32_t previter = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+
+ *iter = (int)previter;
+ *count = max_ii(0, min_ii(state->chunk_size, state->stop - previter));
+
+ return (previter < state->stop);
}
static void parallel_range_func(
TaskPool * __restrict pool,
- void *UNUSED(taskdata),
+ void *userdata_chunk,
int threadid)
{
ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool);
int iter, count;
- const bool use_userdata_chunk = (state->func_ex != NULL) &&
- (state->userdata_chunk_size != 0) && (state->userdata_chunk != NULL);
- void *userdata_chunk = use_userdata_chunk ? MALLOCA(state->userdata_chunk_size) : NULL;
-
while (parallel_range_next_iter_get(state, &iter, &count)) {
int i;
if (state->func_ex) {
- if (use_userdata_chunk) {
- memcpy(userdata_chunk, state->userdata_chunk, state->userdata_chunk_size);
- }
-
for (i = 0; i < count; ++i) {
state->func_ex(state->userdata, userdata_chunk, iter + i, threadid);
}
@@ -639,8 +810,6 @@ static void parallel_range_func(
}
}
}
-
- MALLOCA_FREE(userdata_chunk, state->userdata_chunk_size);
}
/**
@@ -655,6 +824,7 @@ static void task_parallel_range_ex(
const size_t userdata_chunk_size,
TaskParallelRangeFunc func,
TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
const bool use_threading,
const bool use_dynamic_scheduling)
{
@@ -663,6 +833,10 @@ static void task_parallel_range_ex(
ParallelRangeState state;
int i, num_threads, num_tasks;
+ void *userdata_chunk_local = NULL;
+ void *userdata_chunk_array = NULL;
+ const bool use_userdata_chunk = (func_ex != NULL) && (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+
if (start == stop) {
return;
}
@@ -678,9 +852,6 @@ static void task_parallel_range_ex(
*/
if (!use_threading) {
if (func_ex) {
- const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
- void *userdata_chunk_local = NULL;
-
if (use_userdata_chunk) {
userdata_chunk_local = MALLOCA(userdata_chunk_size);
memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
@@ -690,6 +861,10 @@ static void task_parallel_range_ex(
func_ex(userdata, userdata_chunk, i, 0);
}
+ if (func_finalize) {
+ func_finalize(userdata, userdata_chunk);
+ }
+
MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
}
else {
@@ -711,12 +886,9 @@ static void task_parallel_range_ex(
*/
num_tasks = num_threads * 2;
- BLI_spin_init(&state.lock);
state.start = start;
state.stop = stop;
state.userdata = userdata;
- state.userdata_chunk = userdata_chunk;
- state.userdata_chunk_size = userdata_chunk_size;
state.func = func;
state.func_ex = func_ex;
state.iter = start;
@@ -727,23 +899,41 @@ static void task_parallel_range_ex(
state.chunk_size = max_ii(1, (stop - start) / (num_tasks));
}
- num_tasks = max_ii(1, (stop - start) / state.chunk_size);
+ num_tasks = min_ii(num_tasks, (stop - start) / state.chunk_size);
+ atomic_fetch_and_add_uint32((uint32_t *)(&state.iter), 0);
+
+ if (use_userdata_chunk) {
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ }
for (i = 0; i < num_tasks; i++) {
- BLI_task_pool_push(task_pool,
- parallel_range_func,
- NULL, false,
- TASK_PRIORITY_HIGH);
+ if (use_userdata_chunk) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push_from_thread(task_pool,
+ parallel_range_func,
+ userdata_chunk_local, false,
+ TASK_PRIORITY_HIGH, 0);
}
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
- BLI_spin_end(&state.lock);
+ if (use_userdata_chunk) {
+ if (func_finalize) {
+ for (i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ func_finalize(userdata, userdata_chunk_local);
+ }
+ }
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ }
}
/**
- * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement.
+ * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement.
*
* \param start First index to process.
* \param stop Index to stop looping (excluded).
@@ -767,7 +957,7 @@ void BLI_task_parallel_range_ex(
const bool use_dynamic_scheduling)
{
task_parallel_range_ex(
- start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex,
+ start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, NULL,
use_threading, use_dynamic_scheduling);
}
@@ -788,9 +978,153 @@ void BLI_task_parallel_range(
TaskParallelRangeFunc func,
const bool use_threading)
{
- task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, use_threading, false);
+ task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, NULL, use_threading, false);
+}
+
+/**
+ * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement,
+ * with an additional 'finalize' func called from calling thread once whole range have been processed.
+ *
+ * \param start First index to process.
+ * \param stop Index to stop looping (excluded).
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data
+ * (similar to OpenMP's firstprivate).
+ * \param userdata_chunk_size Memory size of \a userdata_chunk.
+ * \param func_ex Callback function (advanced version).
+ * \param func_finalize Callback function, called after all workers have finisehd, useful to finalize accumulative tasks.
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
+ * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently).
+ */
+void BLI_task_parallel_range_finalize(
+ int start, int stop,
+ void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
+ const bool use_threading,
+ const bool use_dynamic_scheduling)
+{
+ task_parallel_range_ex(
+ start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, func_finalize,
+ use_threading, use_dynamic_scheduling);
}
#undef MALLOCA
#undef MALLOCA_FREE
+typedef struct ParallelListbaseState {
+ void *userdata;
+ TaskParallelListbaseFunc func;
+
+ int chunk_size;
+ int index;
+ Link *link;
+ SpinLock lock;
+} ParallelListState;
+
+BLI_INLINE Link *parallel_listbase_next_iter_get(
+ ParallelListState * __restrict state,
+ int * __restrict index,
+ int * __restrict count)
+{
+ int task_count = 0;
+ BLI_spin_lock(&state->lock);
+ Link *result = state->link;
+ if (LIKELY(result != NULL)) {
+ *index = state->index;
+ while (state->link != NULL && task_count < state->chunk_size) {
+ ++task_count;
+ state->link = state->link->next;
+ }
+ state->index += task_count;
+ }
+ BLI_spin_unlock(&state->lock);
+ *count = task_count;
+ return result;
+}
+
+static void parallel_listbase_func(
+ TaskPool * __restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ ParallelListState * __restrict state = BLI_task_pool_userdata(pool);
+ Link *link;
+ int index, count;
+
+ while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
+ for (int i = 0; i < count; ++i) {
+ state->func(state->userdata, link, index + i);
+ link = link->next;
+ }
+ }
+}
+
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase The double linked list to loop over.
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param func Callback function.
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ *
+ * \note There is no static scheduling here, since it would need another full loop over items to count them...
+ */
+void BLI_task_parallel_listbase(
+ struct ListBase *listbase,
+ void *userdata,
+ TaskParallelListbaseFunc func,
+ const bool use_threading)
+{
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParallelListState state;
+ int i, num_threads, num_tasks;
+
+ if (BLI_listbase_is_empty(listbase)) {
+ return;
+ }
+
+ if (!use_threading) {
+ i = 0;
+ for (Link *link = listbase->first; link != NULL; link = link->next, ++i) {
+ func(userdata, link, i);
+ }
+ return;
+ }
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &state);
+ num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+
+ /* The idea here is to prevent creating task for each of the loop iterations
+ * and instead have tasks which are evenly distributed across CPU cores and
+ * pull next iter to be crunched using the queue.
+ */
+ num_tasks = num_threads * 2;
+
+ state.index = 0;
+ state.link = listbase->first;
+ state.userdata = userdata;
+ state.func = func;
+ state.chunk_size = 32;
+ BLI_spin_init(&state.lock);
+
+ for (i = 0; i < num_tasks; i++) {
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push_from_thread(task_pool,
+ parallel_listbase_func,
+ NULL, false,
+ TASK_PRIORITY_HIGH, 0);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ BLI_spin_end(&state.lock);
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a5267175dfa..d6e2f237be9 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4926,6 +4926,9 @@ static void direct_link_pose(FileData *fd, bPose *pose)
pchan->child = newdataadr(fd, pchan->child);
pchan->custom_tx = newdataadr(fd, pchan->custom_tx);
+ pchan->bbone_prev = newdataadr(fd, pchan->bbone_prev);
+ pchan->bbone_next = newdataadr(fd, pchan->bbone_next);
+
direct_link_constraints(fd, &pchan->constraints);
pchan->prop = newdataadr(fd, pchan->prop);
@@ -6159,6 +6162,11 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
for (gps = gpf->strokes.first; gps; gps = gps->next) {
gps->points = newdataadr(fd, gps->points);
+
+ /* the triangulation is not saved, so need to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->triangles = NULL;
+ gps->tot_triangles = 0;
}
}
}
@@ -7447,9 +7455,13 @@ static void direct_link_mask(FileData *fd, Mask *mask)
MaskSpline *spline;
MaskLayerShape *masklay_shape;
+ /* can't use newdataadr since it's a pointer within an array */
+ MaskSplinePoint *act_point_search = NULL;
+
link_list(fd, &masklay->splines);
for (spline = masklay->splines.first; spline; spline = spline->next) {
+ MaskSplinePoint *points_old = spline->points;
int i;
spline->points = newdataadr(fd, spline->points);
@@ -7460,6 +7472,14 @@ static void direct_link_mask(FileData *fd, Mask *mask)
if (point->tot_uw)
point->uw = newdataadr(fd, point->uw);
}
+
+ /* detect active point */
+ if ((act_point_search == NULL) &&
+ (masklay->act_point >= points_old) &&
+ (masklay->act_point < points_old + spline->tot_point))
+ {
+ act_point_search = &spline->points[masklay->act_point - points_old];
+ }
}
link_list(fd, &masklay->splines_shapes);
@@ -7477,7 +7497,7 @@ static void direct_link_mask(FileData *fd, Mask *mask)
}
masklay->act_spline = newdataadr(fd, masklay->act_spline);
- masklay->act_point = newdataadr(fd, masklay->act_point);
+ masklay->act_point = act_point_search;
}
}
@@ -8206,7 +8226,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
- /* don't forget to set version number in BKE_blender.h! */
+ /* don't forget to set version number in BKE_blender_version.h! */
}
#if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b9191d545ed..0ea4078a5cb 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -34,6 +34,7 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
@@ -137,6 +138,40 @@ static void do_version_constraints_stretch_to_limits(ListBase *lb)
}
}
+static void do_version_action_editor_properties_region(ListBase *regionbase)
+{
+ ARegion *ar;
+
+ for (ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_UI) {
+ /* already exists */
+ return;
+ }
+ else if (ar->regiontype == RGN_TYPE_WINDOW) {
+ /* add new region here */
+ ARegion *arnew = MEM_callocN(sizeof(ARegion), "buttons for action");
+
+ BLI_insertlinkbefore(regionbase, ar, arnew);
+
+ arnew->regiontype = RGN_TYPE_UI;
+ arnew->alignment = RGN_ALIGN_RIGHT;
+ arnew->flag = RGN_FLAG_HIDDEN;
+
+ return;
+ }
+ }
+}
+
+static void do_version_bones_super_bbone(ListBase *lb)
+{
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
+ do_version_bones_super_bbone(&bone->childbase);
+ }
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1040,6 +1075,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ /* init grease pencil smooth level iterations */
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->draw_smoothlvl == 0) {
+ gpl->draw_smoothlvl = 1;
+ }
+ }
+ }
+
for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -1072,5 +1116,89 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ CurvePaintSettings *cps = &scene->toolsettings->curve_paint_settings;
+ if (cps->error_threshold == 0) {
+ cps->curve_type = CU_BEZIER;
+ cps->flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
+ cps->error_threshold = 8;
+ cps->radius_max = 1.0f;
+ cps->corner_angle = DEG2RADF(70.0f);
+ }
+ }
+
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ Sequence *seq;
+
+ SEQ_BEGIN (scene->ed, seq)
+ {
+ if (seq->type == SEQ_TYPE_TEXT) {
+ TextVars *data = seq->effectdata;
+ if (data->color[3] == 0.0f) {
+ copy_v4_fl(data->color, 1.0f);
+ data->shadow_color[3] = 1.0f;
+ }
+ }
+ }
+ SEQ_END
+ }
+
+ /* Adding "Properties" region to DopeSheet */
+ for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ /* handle pushed-back space data first */
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sl;
+ do_version_action_editor_properties_region(&saction->regionbase);
+ }
+ }
+
+ /* active spacedata info must be handled too... */
+ if (sa->spacetype == SPACE_ACTION) {
+ do_version_action_editor_properties_region(&sa->regionbase);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 277, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "scaleIn")) {
+ for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
+ do_version_bones_super_bbone(&arm->bonebase);
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ if (ob->pose) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* see do_version_bones_super_bbone()... */
+ pchan->scaleIn = 1.0f;
+ pchan->scaleOut = 1.0f;
+
+ /* also make sure some legacy (unused for over a decade) flags are unset,
+ * so that we can reuse them for stuff that matters now...
+ * (i.e. POSE_IK_MAT, (unknown/unused x 4), POSE_HAS_IK)
+ *
+ * These seem to have been runtime flags used by the IK solver, but that stuff
+ * should be able to be recalculated automatically anyway, so it should be fine.
+ */
+ pchan->flag &= ~((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8));
+ }
+ }
+ }
+ }
+ }
+
+ {
+ for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
+ if (camera->stereo.pole_merge_angle_from == 0.0f &&
+ camera->stereo.pole_merge_angle_to == 0.0f)
+ {
+ camera->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
+ camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 4871dc2f161..124b1efddac 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -145,7 +145,7 @@
#include "BLI_mempool.h"
#include "BKE_action.h"
-#include "BKE_blender.h"
+#include "BKE_blender_version.h"
#include "BKE_bpath.h"
#include "BKE_curve.h"
#include "BKE_constraint.h"
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index efd59c3fa94..3838e8c827c 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -54,6 +54,7 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
+bool BLT_lang_is_ime_supported(void);
/* The "translation-marker" macro. */
#define N_(msgid) msgid
diff --git a/source/blender/blentranslation/CMakeLists.txt b/source/blender/blentranslation/CMakeLists.txt
index 59bd7f0adfa..a3e85344027 100644
--- a/source/blender/blentranslation/CMakeLists.txt
+++ b/source/blender/blentranslation/CMakeLists.txt
@@ -53,4 +53,10 @@ if(WITH_PYTHON)
)
endif()
+if(WIN32)
+ if(WITH_INPUT_IME)
+ add_definitions(-DWITH_INPUT_IME)
+ endif()
+endif()
+
blender_add_lib(bf_blentranslation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 1ad62fa5869..74c2b4b7472 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -54,6 +54,10 @@
#include "MEM_guardedalloc.h"
+/* Cached IME support flags */
+static bool ime_is_lang_supported = false;
+static void blt_lang_check_ime_supported(void);
+
#ifdef WITH_INTERNATIONAL
#include "boost_locale_wrapper.h"
@@ -280,6 +284,7 @@ void BLT_lang_set(const char *str)
#else
(void)str;
#endif
+ blt_lang_check_ime_supported();
}
/* Get the current locale (short code, e.g. es_ES). */
@@ -355,3 +360,32 @@ void BLT_lang_locale_explode(
MEM_freeN(_t);
}
}
+
+/* Test if the translation context allows IME input - used to
+ * avoid weird character drawing if IME inputs non-ascii chars.
+ */
+static void blt_lang_check_ime_supported(void)
+{
+#ifdef WITH_INPUT_IME
+ const char *uilng = BLT_lang_get();
+ if (U.transopts & USER_DOTRANSLATE) {
+ ime_is_lang_supported = STREQ(uilng, "zh_CN") ||
+ STREQ(uilng, "zh_TW") ||
+ STREQ(uilng, "ja_JP");
+ }
+ else {
+ ime_is_lang_supported = false;
+ }
+#else
+ ime_is_lang_supported = false;
+#endif
+}
+
+bool BLT_lang_is_ime_supported(void)
+{
+#ifdef WITH_INPUT_IME
+ return ime_is_lang_supported;
+#else
+ return false;
+#endif
+}
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index f7e709ce9cc..1d68cdcf28a 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -1246,7 +1246,6 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE);
BMVert *v1 = NULL, *v2 = NULL;
- const char *err = NULL;
int i, tote = 0;
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -1267,7 +1266,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF);
if (rlen > 2) {
- err = N_("Input faces do not form a contiguous manifold region");
+ /* Input faces do not form a contiguous manifold region */
goto error;
}
else if (rlen == 1) {
@@ -1288,7 +1287,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
* else this will remove the face as well - campbell */
- if (!BM_edge_face_count_is_over(l_iter->e, 3)) {
+ if (!BM_edge_face_count_is_over(l_iter->e, 2)) {
if (do_del) {
BLI_array_append(deledges, l_iter->e);
}
@@ -1328,9 +1327,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
/* create region face */
f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL;
- if (UNLIKELY(!f_new || BMO_error_occurred(bm))) {
- if (!BMO_error_occurred(bm))
- err = N_("Invalid boundary region to join faces");
+ if (UNLIKELY(f_new == NULL)) {
+ /* Invalid boundary region to join faces */
goto error;
}
@@ -1426,9 +1424,6 @@ error:
BLI_array_free(deledges);
BLI_array_free(delverts);
- if (err) {
- BMO_error_raise(bm, bm->currentop, BMERR_DISSOLVEFACES_FAILED, err);
- }
return NULL;
}
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index c5c9403884b..882d78ce6b3 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -161,6 +161,7 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
break;
}
case DEL_FACES:
+ case DEL_FACES_KEEP_BOUNDARY:
{
/* go through and mark all edges and all verts of all faces for delete */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
@@ -190,11 +191,20 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
}
/* also mark all the vertices of remaining edges for keeping */
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+
+ /* Only exception to normal 'DEL_FACES' logic. */
+ if (type == DEL_FACES_KEEP_BOUNDARY) {
+ if (BM_edge_is_boundary(e)) {
+ BMO_elem_flag_disable(bm, e, oflag);
+ }
+ }
+
if (!BMO_elem_flag_test(bm, e, oflag)) {
BMO_elem_flag_disable(bm, e->v1, oflag);
BMO_elem_flag_disable(bm, e->v2, oflag);
}
}
+
/* now delete marked face */
bmo_remove_tagged_faces(bm, oflag);
/* delete marked edge */
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 4014d29966a..cc79e28a361 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
@@ -250,6 +251,64 @@ void *BMO_iter_as_arrayN(
}
}
+int BM_iter_mesh_bitmap_from_filter(
+ const char itype, BMesh *bm,
+ BLI_bitmap *bitmap,
+ bool (*test_fn)(BMElem *, void *user_data),
+ void *user_data)
+{
+ BMIter iter;
+ BMElem *ele;
+ int i;
+ int bitmap_enabled = 0;
+
+ BM_ITER_MESH_INDEX (ele, &iter, bm, itype, i) {
+ if (test_fn(ele, user_data)) {
+ BLI_BITMAP_ENABLE(bitmap, i);
+ bitmap_enabled++;
+ }
+ else {
+ BLI_BITMAP_DISABLE(bitmap, i);
+ }
+ }
+
+ return bitmap_enabled;
+}
+
+/**
+ * Needed when we want to check faces, but return a loop aligned array.
+ */
+int BM_iter_mesh_bitmap_from_filter_tessface(
+ BMesh *bm,
+ BLI_bitmap *bitmap,
+ bool (*test_fn)(BMFace *, void *user_data),
+ void *user_data)
+{
+ BMIter iter;
+ BMFace *f;
+ int i;
+ int j = 0;
+ int bitmap_enabled = 0;
+
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (test_fn(f, user_data)) {
+ for (int tri = 2; tri < f->len; tri++) {
+ BLI_BITMAP_ENABLE(bitmap, j);
+ bitmap_enabled++;
+ j++;
+ }
+ }
+ else {
+ for (int tri = 2; tri < f->len; tri++) {
+ BLI_BITMAP_DISABLE(bitmap, j);
+ j++;
+ }
+ }
+ }
+
+ return bitmap_enabled;
+}
+
/**
* \brief Elem Iter Flag Count
*
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 336e9d88dea..0551d824131 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -208,6 +208,18 @@ void *BMO_iter_as_arrayN(
int *r_len,
/* optional args to avoid an alloc (normally stack array) */
void **stack_array, int stack_array_size);
+
+int BM_iter_mesh_bitmap_from_filter(
+ const char itype, BMesh *bm,
+ unsigned int *bitmap,
+ bool (*test_fn)(BMElem *, void *user_data),
+ void *user_data);
+int BM_iter_mesh_bitmap_from_filter_tessface(
+ BMesh *bm,
+ unsigned int *bitmap,
+ bool (*test_fn)(BMFace *, void *user_data),
+ void *user_data);
+
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value);
int BM_iter_mesh_count(const char itype, BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 931413d834f..7b102c9283b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -224,7 +224,7 @@ static BMFace *bm_face_create_from_mpoly(
*/
void BM_mesh_bm_from_me(
BMesh *bm, Mesh *me,
- const bool calc_face_normal, const bool set_key, int act_key_nr)
+ const struct BMeshFromMeshParams *params)
{
MVert *mvert;
MEdge *medge;
@@ -237,11 +237,6 @@ void BM_mesh_bm_from_me(
float (*keyco)[3] = NULL;
int totuv, totloops, i, j;
- int cd_vert_bweight_offset;
- int cd_edge_bweight_offset;
- int cd_edge_crease_offset;
- int cd_shape_keyindex_offset;
-
/* free custom data */
/* this isnt needed in most cases but do just incase */
CustomData_free(&bm->vdata, bm->totvert);
@@ -278,16 +273,21 @@ void BM_mesh_bm_from_me(
CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
}
- if ((act_key_nr != 0) && (me->key != NULL)) {
- actkey = BLI_findlink(&me->key->block, act_key_nr - 1);
+ if ((params->active_shapekey != 0) && (me->key != NULL)) {
+ actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
}
else {
actkey = NULL;
}
- if (me->key) {
+ const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
+ const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
+
+ if (tot_shape_keys || params->add_key_index) {
CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ }
+ if (tot_shape_keys) {
/* check if we need to generate unique ids for the shapekeys.
* this also exists in the file reading code, but is here for
* a sanity check */
@@ -305,7 +305,7 @@ void BM_mesh_bm_from_me(
if (actkey && actkey->totelem == me->totvert) {
keyco = actkey->data;
- bm->shapenr = act_key_nr;
+ bm->shapenr = params->active_shapekey;
}
for (i = 0, block = me->key->block.first; block; block = block->next, i++) {
@@ -314,6 +314,8 @@ void BM_mesh_bm_from_me(
j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
bm->vdata.layers[j].uid = block->uid;
+
+ shape_key_table[i] = (const float (*)[3])block->data;
}
}
@@ -324,13 +326,17 @@ void BM_mesh_bm_from_me(
BM_mesh_cd_flag_apply(bm, me->cd_flag);
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
- cd_shape_keyindex_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
+ const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1;
+ const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ?
+ CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
- v = vtable[i] = BM_vert_create(bm, keyco && set_key ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
+ v = vtable[i] = BM_vert_create(
+ bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL,
+ BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* transfer flag */
@@ -348,17 +354,14 @@ void BM_mesh_bm_from_me(
if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
- /* set shapekey data */
- if (me->key) {
- /* set shape key original index */
- if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
-
- for (block = me->key->block.first, j = 0; block; block = block->next, j++) {
- float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, j);
+ /* set shape key original index */
+ if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
- if (co) {
- copy_v3_v3(co, ((float *)block->data) + 3 * i);
- }
+ /* set shapekey data */
+ if (tot_shape_keys) {
+ float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
+ for (j = 0; j < tot_shape_keys; j++, co_dst++) {
+ copy_v3_v3(*co_dst, shape_key_table[j][i]);
}
}
}
@@ -438,7 +441,7 @@ void BM_mesh_bm_from_me(
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true);
- if (calc_face_normal) {
+ if (params->calc_face_normal) {
BM_face_normal_update(f);
}
}
@@ -511,7 +514,12 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
if (cd_shape_keyindex_offset != -1) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
- if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert)) {
+ if ((keyi != ORIGINDEX_NONE) &&
+ (keyi < ototvert) &&
+ /* not fool-proof, but chances are if we have many verts with the same index,
+ * we will want to use the first one, since the second is more likely to be a duplicate. */
+ (vertMap[keyi] == NULL))
+ {
vertMap[keyi] = eve;
}
}
@@ -568,7 +576,9 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
-void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
+void BM_mesh_bm_to_me(
+ BMesh *bm, Mesh *me,
+ const struct BMeshToMeshParams *params)
{
MLoop *mloop;
MPoly *mpoly;
@@ -629,10 +639,13 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
me->totface = 0;
me->act_face = -1;
- CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
- CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
- CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop);
- CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly);
+ {
+ const CustomDataMask mask = CD_MASK_MESH | params->cd_mask_extra;
+ CustomData_copy(&bm->vdata, &me->vdata, mask, CD_CALLOC, me->totvert);
+ CustomData_copy(&bm->edata, &me->edata, mask, CD_CALLOC, me->totedge);
+ CustomData_copy(&bm->ldata, &me->ldata, mask, CD_CALLOC, me->totloop);
+ CustomData_copy(&bm->pdata, &me->pdata, mask, CD_CALLOC, me->totpoly);
+ }
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
@@ -781,11 +794,11 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
if (vertMap) MEM_freeN(vertMap);
}
- if (do_tessface) {
+ if (params->calc_tessface) {
BKE_mesh_tessface_calc(me);
}
- BKE_mesh_update_customdata_pointers(me, do_tessface);
+ BKE_mesh_update_customdata_pointers(me, params->calc_tessface);
{
BMEditSelection *selected;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index ce286f6c662..7cbfe2d9210 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -39,9 +39,28 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
+
+struct BMeshFromMeshParams {
+ unsigned int calc_face_normal : 1;
+ /* add a vertex CD_SHAPE_KEYINDEX layer */
+ unsigned int add_key_index : 1;
+ /* set vertex coordinates from the shapekey */
+ unsigned int use_shapekey : 1;
+ /* define the active shape key (index + 1) */
+ int active_shapekey;
+};
void BM_mesh_bm_from_me(
BMesh *bm, struct Mesh *me,
- const bool calc_face_normal, const bool set_key, int act_key_nr);
-void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface);
+ const struct BMeshFromMeshParams *params)
+ATTR_NONNULL(1, 3);
+
+struct BMeshToMeshParams {
+ unsigned int calc_tessface : 1;
+ int64_t cd_mask_extra;
+};
+void BM_mesh_bm_to_me(
+ BMesh *bm, struct Mesh *me,
+ const struct BMeshToMeshParams *params)
+ATTR_NONNULL(1, 2, 3);
#endif /* __BMESH_MESH_CONV_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 14e9bf81be7..cf93fe0935e 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -285,6 +285,9 @@ enum {
DEL_ONLYFACES,
DEL_EDGESFACES,
DEL_FACES,
+ /* A version of 'DEL_FACES' that keeps edges on face boundaries,
+ * allowing the surrounding edge-loop to be kept from removed face regions. */
+ DEL_FACES_KEEP_BOUNDARY,
DEL_ONLYTAGGED
};
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index ffad3e59e47..9b074dc4db4 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -2186,14 +2186,13 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
{
BMIter viter;
BMFace *f;
- int i;
bool is_init = false;
bool is_overlap = false;
LinkNode *f_lnk = NULL;
#ifdef DEBUG
/* check flag isn't already set */
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BLI_assert(BM_ELEM_API_FLAG_TEST(varr[i], _FLAG_OVERLAP) == 0);
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
BLI_assert(BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0);
@@ -2201,7 +2200,7 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
}
#endif
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) {
/* check if all vers in this face are flagged*/
@@ -2209,8 +2208,8 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
if (is_init == false) {
is_init = true;
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_ENABLE(varr[i], _FLAG_OVERLAP);
+ for (int j = 0; j < len; j++) {
+ BM_ELEM_API_FLAG_ENABLE(varr[j], _FLAG_OVERLAP);
}
}
@@ -2234,7 +2233,7 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
}
if (is_init == true) {
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BM_ELEM_API_FLAG_DISABLE(varr[i], _FLAG_OVERLAP);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h
index 430ba10fb42..09cf39b526d 100644
--- a/source/blender/bmesh/intern/bmesh_queries_inline.h
+++ b/source/blender/bmesh/intern/bmesh_queries_inline.h
@@ -146,6 +146,13 @@ BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
return (ELEM(l_b, l_a->next, l_a->prev));
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
+BLI_INLINE bool BM_loop_is_manifold(const BMLoop *l)
+{
+ return ((l != l->radial_next) &&
+ (l == l->radial_next->radial_next));
+}
+
/**
* Check if we have a single wire edge user.
*/
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index f5a801a31c3..b2373a069db 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -125,6 +125,7 @@ enum {
BMW_LOOPDATA_ISLAND,
BMW_ISLANDBOUND,
BMW_ISLAND,
+ BMW_ISLAND_MANIFOLD,
BMW_CONNECTED_VERTEX,
/* end of array index enum vals */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 627f8358410..018700c0efa 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -711,13 +711,6 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
e = l->e;
v = BM_edge_other_vert(e, iwalk->lastv);
-
- if (!BM_vert_is_manifold(v)) {
- BMW_reset(walker);
- BMO_error_raise(walker->bm, NULL, BMERR_WALKER_FAILED,
- "Non-manifold vert while searching region boundary");
- return NULL;
- }
/* pop off current state */
BMW_state_remove(walker);
@@ -726,7 +719,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
while (1) {
l = BM_loop_other_edge_loop(l, v);
- if (l != l->radial_next) {
+ if (BM_loop_is_manifold(l)) {
l = l->radial_next;
f = l->f;
e = l->e;
@@ -737,6 +730,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
}
}
else {
+ /* treat non-manifold edges as boundaries */
f = l->f;
e = l->e;
break;
@@ -791,25 +785,44 @@ static void *bmw_IslandWalker_yield(BMWalker *walker)
return iwalk->cur;
}
-static void *bmw_IslandWalker_step(BMWalker *walker)
+static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
{
BMwIslandWalker *iwalk, owalk;
- BMIter iter, liter;
- BMFace *f;
- BMLoop *l;
+ BMLoop *l_iter, *l_first;
BMW_state_remove_r(walker, &owalk);
iwalk = &owalk;
- l = BM_iter_new(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
- for ( ; l; l = BM_iter_step(&liter)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(iwalk->cur);
+ do {
/* could skip loop here too, but don't add unless we need it */
- if (!bmw_mask_check_edge(walker, l->e)) {
+ if (!bmw_mask_check_edge(walker, l_iter->e)) {
continue;
}
- f = BM_iter_new(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
- for ( ; f; f = BM_iter_step(&iter)) {
+ BMLoop *l_radial_iter;
+
+ if (only_manifold && (l_iter->radial_next != l_iter)) {
+ int face_count = 1;
+ /* check other faces (not this one), ensure only one other can be walked onto. */
+ l_radial_iter = l_iter->radial_next;
+ do {
+ if (bmw_mask_check_face(walker, l_radial_iter->f)) {
+ face_count++;
+ if (face_count == 3) {
+ break;
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+
+ if (face_count != 2) {
+ continue;
+ }
+ }
+
+ l_radial_iter = l_iter;
+ while ((l_radial_iter = l_radial_iter->radial_next) != l_iter) {
+ BMFace *f = l_radial_iter->f;
if (!bmw_mask_check_face(walker, f)) {
continue;
@@ -823,17 +836,30 @@ static void *bmw_IslandWalker_step(BMWalker *walker)
if (BLI_gset_haskey(walker->visit_set, f)) {
continue;
}
-
+
iwalk = BMW_state_add(walker);
iwalk->cur = f;
BLI_gset_insert(walker->visit_set, f);
break;
}
- }
-
+ } while ((l_iter = l_iter->next) != l_first);
+
return owalk.cur;
}
+static void *bmw_IslandWalker_step(BMWalker *walker)
+{
+ return bmw_IslandWalker_step_ex(walker, false);
+}
+
+/**
+ * Ignore edges that don't have 2x usable faces.
+ */
+static void *bmw_IslandManifoldWalker_step(BMWalker *walker)
+{
+ return bmw_IslandWalker_step_ex(walker, true);
+}
+
/** \} */
@@ -1608,6 +1634,16 @@ static BMWalker bmw_IslandWalker_Type = {
BM_EDGE | BM_FACE, /* valid restrict masks */
};
+static BMWalker bmw_IslandManifoldWalker_Type = {
+ BM_FACE,
+ bmw_IslandWalker_begin,
+ bmw_IslandManifoldWalker_step, /* only difference with BMW_ISLAND */
+ bmw_IslandWalker_yield,
+ sizeof(BMwIslandWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE | BM_FACE, /* valid restrict masks */
+};
+
static BMWalker bmw_EdgeLoopWalker_Type = {
BM_EDGE,
bmw_EdgeLoopWalker_begin,
@@ -1680,6 +1716,7 @@ BMWalker *bm_walker_types[] = {
&bmw_UVEdgeWalker_Type, /* BMW_LOOPDATA_ISLAND */
&bmw_IslandboundWalker_Type, /* BMW_ISLANDBOUND */
&bmw_IslandWalker_Type, /* BMW_ISLAND */
+ &bmw_IslandManifoldWalker_Type, /* BMW_ISLAND_MANIFOLD */
&bmw_ConnectedVertexWalker_Type, /* BMW_CONNECTED_VERTEX */
};
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index c7bf481d7d5..a0149a41921 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -262,7 +262,7 @@ static void bridge_loop_pair(
if (bm->totface) {
struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b};
int i;
- int winding_votes = 0;
+ int winding_votes[2] = {0, 0};
int winding_dir = 1;
for (i = 0; i < 2; i++, winding_dir = -winding_dir) {
LinkData *el;
@@ -271,15 +271,49 @@ static void bridge_loop_pair(
if (el_next) {
BMEdge *e = BM_edge_exists(el->data, el_next->data);
if (e && BM_edge_is_boundary(e)) {
- winding_votes += ((e->l->v == el->data) ? winding_dir : -winding_dir);
+ winding_votes[i] += ((e->l->v == el->data) ? winding_dir : -winding_dir);
}
}
}
}
- if (winding_votes < 0) {
- BM_edgeloop_flip(bm, el_store_a);
- BM_edgeloop_flip(bm, el_store_b);
+ if (winding_votes[0] || winding_votes[1]) {
+ bool flip[2] = {false, false};
+
+ /* for direction aligned loops we can't rely on the directly we have,
+ * use the winding defined by the connected faces (see T48356). */
+ if (fabsf(dot_a) < eps) {
+ if (winding_votes[0] < 0) {
+ flip[0] = !flip[0];
+ winding_votes[0] *= -1;
+
+ }
+ }
+ if (fabsf(dot_b) < eps) {
+ if (winding_votes[1] < 0) {
+ flip[1] = !flip[1];
+ winding_votes[1] *= -1;
+ }
+ }
+
+ /* when both loops contradict the winding, flip them so surrounding geometry matches */
+ if ((winding_votes[0] + winding_votes[1]) < 0) {
+ flip[0] = !flip[0];
+ flip[1] = !flip[1];
+
+ /* valid but unused */
+#if 0
+ winding_votes[0] *= -1;
+ winding_votes[1] *= -1;
+#endif
+ }
+
+ if (flip[0]) {
+ BM_edgeloop_flip(bm, el_store_a);
+ }
+ if (flip[1]) {
+ BM_edgeloop_flip(bm, el_store_b);
+ }
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index c8dff4a8598..86062ff0b66 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -43,6 +43,7 @@
#define FACE_MARK 1
#define FACE_ORIG 2
#define FACE_NEW 4
+#define FACE_TAG 8
#define EDGE_MARK 1
#define EDGE_TAG 2
@@ -156,19 +157,19 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
}
}
- BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK);
+ BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK | FACE_TAG);
/* collect region */
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
BMFace *f_iter;
- if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
continue;
}
BLI_array_empty(faces);
faces = NULL; /* forces different allocatio */
- BMW_init(&regwalker, bm, BMW_ISLAND,
+ BMW_init(&regwalker, bm, BMW_ISLAND_MANIFOLD,
BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK,
BMW_FLAG_NOP, /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo */
BMW_NIL_LAY);
@@ -180,7 +181,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
for (i = 0; i < BLI_array_count(faces); i++) {
f_iter = faces[i];
- BMO_elem_flag_disable(bm, f_iter, FACE_MARK);
+ BMO_elem_flag_disable(bm, f_iter, FACE_TAG);
BMO_elem_flag_enable(bm, f_iter, FACE_ORIG);
}
@@ -193,7 +194,10 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BLI_array_append(faces, NULL);
BLI_array_append(regions, faces);
}
-
+
+ /* track how many faces we should end up with */
+ int totface_target = bm->totface;
+
for (i = 0; i < BLI_array_count(regions); i++) {
BMFace *f_new;
int tot = 0;
@@ -215,6 +219,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
if (act_face && bm->act_face == NULL) {
bm->act_face = f_new;
}
+ totface_target -= tot - 1;
}
else {
BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED,
@@ -226,11 +231,12 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
* unmark the original faces for deletion */
BMO_elem_flag_disable(bm, f_new, FACE_ORIG);
BMO_elem_flag_enable(bm, f_new, FACE_NEW);
-
}
- BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
-
+ /* Typically no faces need to be deleted */
+ if (totface_target != bm->totface) {
+ BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
+ }
if (use_verts) {
BMIter viter;
diff --git a/source/blender/bmesh/operators/bmo_mesh_conv.c b/source/blender/bmesh/operators/bmo_mesh_conv.c
index d124aaaf80e..0eb9bf90ca8 100644
--- a/source/blender/bmesh/operators/bmo_mesh_conv.c
+++ b/source/blender/bmesh/operators/bmo_mesh_conv.c
@@ -45,7 +45,10 @@ void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op)
Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh");
bool set_key = BMO_slot_bool_get(op->slots_in, "use_shapekey");
- BM_mesh_bm_from_me(bm, me, false, set_key, ob->shapenr);
+ BM_mesh_bm_from_me(
+ bm, me, (&(struct BMeshFromMeshParams){
+ .use_shapekey = set_key, .active_shapekey = ob->shapenr,
+ }));
if (me->key && ob->shapenr > me->key->totkey) {
ob->shapenr = me->key->totkey - 1;
@@ -69,5 +72,5 @@ void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op)
/* Object *ob = BMO_slot_ptr_get(op, "object"); */
const bool dotess = !BMO_slot_bool_get(op->slots_in, "skip_tessface");
- BM_mesh_bm_to_me(bm, me, dotess);
+ BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){ .calc_tessface = dotess, }));
}
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index fcf02c4bc3f..b120b48447f 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -376,8 +376,8 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
phid /= 2;
for (a = 0; a <= tot; a++) {
/* Going in this direction, then edge extruding, makes normals face outward */
- vec[0] = -dia * sinf(phi);
- vec[1] = 0.0;
+ vec[0] = 0.0;
+ vec[1] = dia * sinf(phi);
vec[2] = dia * cosf(phi);
eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, eve, VERT_MARK);
@@ -1042,13 +1042,14 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
int i, x, y, z;
+ /* rotation order set to match 'BM_mesh_calc_uvs_cube' */
const char faces[6][4] = {
- {1, 3, 2, 0},
- {3, 7, 6, 2},
- {7, 5, 4, 6},
- {5, 1, 0, 4},
- {0, 2, 6, 4},
- {5, 7, 3, 1},
+ {0, 1, 3, 2},
+ {2, 3, 7, 6},
+ {6, 7, 5, 4},
+ {4, 5, 1, 0},
+ {2, 6, 4, 0},
+ {7, 3, 1, 5},
};
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
@@ -1093,7 +1094,8 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
/**
* Fills first available UVmap with cube-like UVs for all faces OpFlag-ged by given flag.
*
- * \note Expects tagged faces to be six quads...
+ * \note Expects tagged faces to be six quads.
+ * \note Caller must order faces for correct alignment.
*
* \param bm The BMesh to operate on.
* \param oflag The flag to check faces with.
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index a1460cec7d1..ad35d57f35b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -37,6 +37,9 @@
#include "bmesh.h"
#include "bmesh_decimate.h" /* own include */
+/* check that collapsing a vertex between 2 edges doesn't cause a degenerate face. */
+#define USE_DEGENERATE_CHECK
+
#define COST_INVALID FLT_MAX
@@ -88,9 +91,6 @@ static float bm_edge_calc_dissolve_error(
const BMEdge *e, const BMO_Delimit delimit,
const struct DelimitData *delimit_data)
{
- const bool is_contig = BM_edge_is_contiguous(e);
- float angle;
-
if (!BM_edge_is_manifold(e)) {
goto fail;
}
@@ -113,6 +113,8 @@ static float bm_edge_calc_dissolve_error(
goto fail;
}
+ const bool is_contig = BM_edge_is_contiguous(e);
+
if ((delimit & BMO_DELIM_NORMAL) &&
(is_contig == false))
{
@@ -125,18 +127,136 @@ static float bm_edge_calc_dissolve_error(
goto fail;
}
- angle = BM_edge_calc_face_angle(e);
- if (is_contig == false) {
- angle = (float)M_PI - angle;
+ float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
+ if (is_contig) {
+ angle_cos_neg *= -1;
}
- return angle;
+ return angle_cos_neg;
fail:
return COST_INVALID;
}
+#ifdef USE_DEGENERATE_CHECK
+
+static void mul_v2_m3v3_center(float r[2], float m[3][3], const float a[3], const float center[3])
+{
+ BLI_assert(r != a);
+ BLI_assert(r != center);
+
+ float co[3];
+ sub_v3_v3v3(co, a, center);
+
+ r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
+ r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
+}
+
+static bool bm_loop_collapse_is_degenerate(BMLoop *l_ear)
+{
+ /* calculate relative to the centeral vertex for higher precision */
+ const float *center = l_ear->v->co;
+
+ float tri_2d[3][2];
+ float axis_mat[3][3];
+
+ axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
+
+ {
+ mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
+#if 0
+ mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
+#else
+ zero_v2(tri_2d[1]);
+#endif
+ mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
+ }
+
+ /* check we're not flipping face corners before or after the ear */
+ {
+ float adjacent_2d[2];
+
+ if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2])))
+ {
+ return true;
+ }
+ }
+
+ if (!BM_vert_is_edge_pair(l_ear->next->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0])))
+ {
+ return true;
+ }
+ }
+ }
+
+ /* check no existing verts are inside the triangle */
+ {
+ /* triangle may be concave, if so - flip so we can use clockwise check */
+ if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
+ swap_v2_v2(tri_2d[1], tri_2d[2]);
+ }
+
+ /* skip l_ear and adjacent verts */
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_ear->next->next;
+ l_first = l_ear->prev;
+ do {
+ float co_2d[2];
+ mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
+ if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
+ return true;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return false;
+}
+
+static bool bm_vert_collapse_is_degenerate(BMVert *v)
+{
+ BMEdge *e_pair[2];
+ BMVert *v_pair[2];
+
+ if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
+
+ /* allow wire edges */
+ if (BM_edge_is_wire(e_pair[0]) || BM_edge_is_wire(e_pair[1])) {
+ return false;
+ }
+
+ v_pair[0] = BM_edge_other_vert(e_pair[0], v);
+ v_pair[1] = BM_edge_other_vert(e_pair[1], v);
+
+ if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_pair[1]->l;
+ do {
+ if (l_iter->f->len > 3) {
+ BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
+ BLI_assert(v == l_pivot->v);
+ if (bm_loop_collapse_is_degenerate(l_pivot)) {
+ return true;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+#endif /* USE_DEGENERATE_CHECK */
+
+
void BM_mesh_decimate_dissolve_ex(
BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
BMO_Delimit delimit,
@@ -144,6 +264,7 @@ void BM_mesh_decimate_dissolve_ex(
BMEdge **einput_arr, const int einput_len,
const short oflag_out)
{
+ const float angle_limit_cos_neg = -cosf(angle_limit);
struct DelimitData delimit_data = {0};
const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
@@ -175,7 +296,6 @@ void BM_mesh_decimate_dissolve_ex(
/* --- setup heap --- */
eheap = BLI_heap_new_ex(einput_len);
- eheap_table = _heap_table;
/* wire -> tag */
BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
@@ -193,7 +313,7 @@ void BM_mesh_decimate_dissolve_ex(
}
while ((BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit))
+ (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg))
{
BMFace *f_new = NULL;
BMEdge *e;
@@ -328,7 +448,14 @@ void BM_mesh_decimate_dissolve_ex(
v = BLI_heap_node_ptr(vnode_top);
i = BM_elem_index_get(v);
- if (BM_vert_is_edge_pair(v)) {
+ if (
+#ifdef USE_DEGENERATE_CHECK
+ !bm_vert_collapse_is_degenerate(v)
+#else
+ BM_vert_is_edge_pair(v)
+#endif
+ )
+ {
e_new = BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
if (e_new) {
@@ -343,7 +470,6 @@ void BM_mesh_decimate_dissolve_ex(
do {
BM_face_normal_update(l_iter->f);
} while ((l_iter = l_iter->radial_next) != l_first);
-
}
/* re-calculate costs */
@@ -355,6 +481,33 @@ void BM_mesh_decimate_dissolve_ex(
vheap_table[j] = BLI_heap_insert(vheap, cost, v_iter);
}
}
+
+#ifdef USE_DEGENERATE_CHECK
+ /* dissolving a vertex may mean vertices we previously weren't able to dissolve
+ * can now be re-evaluated. */
+ if (e_new->l) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = e_new->l;
+ do {
+ /* skip vertices part of this edge, evaluated above */
+ BMLoop *l_cycle_first, *l_cycle_iter;
+ l_cycle_iter = l_iter->next->next;
+ l_cycle_first = l_iter->prev;
+ do {
+ const int j = BM_elem_index_get(l_cycle_iter->v);
+ if (j != -1 && vheap_table[j] &&
+ (BLI_heap_node_value(vheap_table[j]) == COST_INVALID))
+ {
+ const float cost = bm_vert_edge_face_angle(l_cycle_iter->v);
+ BLI_heap_remove(vheap, vheap_table[j]);
+ vheap_table[j] = BLI_heap_insert(vheap, cost, l_cycle_iter->v);
+ }
+ } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
+
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+#endif /* USE_DEGENERATE_CHECK */
+
}
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index e6437aa6c59..9d1f7fa45d2 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -85,6 +85,8 @@
/* insert bl_debug_draw_quad_clear... here */
#endif
+// #define USE_DUMP
+
static void tri_v3_scale(
float v1[3], float v2[3], float v3[3],
const float t)
@@ -652,7 +654,7 @@ static void bm_isect_tri_tri(
#endif
if (e) {
#ifdef USE_DUMP
- printf(" adding to edge %d\n", BM_elem_index_get(e));
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
#endif
edge_verts_add(s, e, fv_b[i_b], true);
}
@@ -769,16 +771,13 @@ 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) {
- /* check this wasn't handled above */
- if (!(side >= IX_EDGE_TRI_EDGE0 && side <= IX_EDGE_TRI_EDGE2)) {
- 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);
+ 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);
#ifdef USE_DUMP
- printf(" ('EDGE-RAY-B', %d),\n", side);
+ printf(" ('EDGE-TRI-B', %d),\n", side);
#endif
- }
}
}
}
@@ -873,7 +872,7 @@ static void raycast_callback(void *userdata,
#endif
#ifdef USE_DUMP
- printf("%s: Adding depth %f\n", __func__, depth);
+ printf("%s: Adding depth %f\n", __func__, dist);
#endif
BLI_buffer_append(raycast_data->z_buffer, float, dist);
}
@@ -909,7 +908,7 @@ static int isect_bvhtree_point_v3(
&raycast_data);
#ifdef USE_DUMP
- printf("%s: Total intersections: %d\n", __func__, raycast_data.num_isect);
+ printf("%s: Total intersections: %d\n", __func__, z_buffer.count);
#endif
int num_isect;
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index 15e95a05425..bd32e989ae3 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -90,7 +90,7 @@ extern "C"
#include "BKE_action.h" // pose functions
#include "BKE_animsys.h"
#include "BKE_armature.h"
-#include "BKE_blender.h" // version info
+#include "BKE_blender_version.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 64df42fc823..a884268fd5e 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -39,7 +39,6 @@
#include "COLLADAFWPolygons.h"
extern "C" {
- #include "BKE_blender.h"
#include "BKE_customdata.h"
#include "BKE_displist.h"
#include "BKE_global.h"
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b1cbc01a9a6..b64b10e0833 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -118,12 +118,11 @@ int collada_export(Scene *sce,
export_settings.export_set = BKE_object_relational_superset(sce, objectSet, (eObRelationTypes)includeFilter);
int export_count = BLI_linklist_count(export_settings.export_set);
- if (export_count==0)
- {
+ if (export_count == 0) {
if (export_settings.selected) {
fprintf(stderr, "Collada: Found no objects to export.\nPlease ensure that all objects which shall be exported are also visible in the 3D Viewport.\n");
}
- else{
+ else {
fprintf(stderr, "Collada: Your scene seems to be empty. No Objects will be exported.\n");
}
}
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index efdfaadd3e2..f8feed8145c 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -357,9 +357,12 @@ void bc_triangulate_mesh(Mesh *me)
int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
- BM_mesh_bm_from_me(bm, me, true, false, 0);
+ BMeshFromMeshParams bm_from_me_params = {0};
+ bm_from_me_params.calc_face_normal = true;
+ BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
BM_mesh_triangulate(bm, quad_method, use_beauty, tag_only, NULL, NULL, NULL);
- BM_mesh_bm_to_me(bm, me, false);
+ BMeshToMeshParams bm_to_me_params = {0};
+ BM_mesh_bm_to_me(bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 35e5ec98e57..3180e7e4154 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -542,11 +542,6 @@ list(APPEND INC
${CMAKE_CURRENT_BINARY_DIR}/operations
)
-if(MSVC AND NOT CMAKE_CL_64)
- set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
-endif()
-
data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl
${CMAKE_CURRENT_BINARY_DIR}/operations/COM_OpenCLKernels.cl.h SRC)
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
index a531493d486..46a70716349 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
@@ -58,7 +58,12 @@ void ColorBalanceNode::convertToOperations(NodeConverter &converter, const Compo
}
else {
ColorBalanceASCCDLOperation *operationCDL = new ColorBalanceASCCDLOperation();
- operationCDL->setOffset(n->offset);
+
+ float offset[3];
+ copy_v3_fl(offset, n->offset_basis);
+ add_v3_v3(offset, n->offset);
+
+ operationCDL->setOffset(offset);
operationCDL->setPower(n->power);
operationCDL->setSlope(n->slope);
operation = operationCDL;
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index c55366ab370..624378f2ae9 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -159,7 +159,11 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
+ int ix = x, iy = y;
+ if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ zero_v4(output);
+ }
+ else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
zero_v4(output);
}
else {
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 543ca0f7c11..099208ce600 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -77,21 +77,19 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
unsigned int offset;
int width = this->getWidth(), height = this->getHeight();
+ int ix = x, iy = y;
+ if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
+ if (this->m_elementsize == 1)
+ output[0] = 0.0f;
+ else if (this->m_elementsize == 3)
+ zero_v3(output);
+ else
+ zero_v4(output);
+ return;
+ }
+
switch (sampler) {
case COM_PS_NEAREST: {
- int ix = x;
- int iy = y;
- if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
- if (this->m_elementsize == 1)
- output[0] = 0.0f;
- else if (this->m_elementsize == 3)
- zero_v3(output);
- else
- zero_v4(output);
- break;
-
- }
-
offset = (iy * width + ix) * this->m_elementsize;
if (this->m_elementsize == 1)
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index e1dc8b020fb..2b4df85f29c 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -83,7 +83,9 @@ set(SRC
util/depsgraph_util_transitive.h
)
-if(HAVE_STD_UNORDERED_MAP_HEADER)
+if(WITH_CXX11)
+ add_definitions(-DDEG_STD_UNORDERED_MAP)
+elseif(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DDEG_STD_UNORDERED_MAP)
else()
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 18c7c5bd8e1..d293d03f63d 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -413,18 +413,28 @@ DepsRelation::DepsRelation(DepsNode *from,
*/
#endif
- /* Hook it up to the nodes which use it. */
- from->outlinks.insert(this);
- to->inlinks.insert(this);
+ /* Hook it up to the nodes which use it.
+ *
+ * NOTE: We register relation in the nodes which this link connects to here
+ * in constructor but we don't unregister it in the destructor.
+ *
+ * Reasoning:
+ *
+ * - Destructor is currently used on global graph destruction, so there's no
+ * real need in avoiding dangling pointers, all the memory is to be freed
+ * anyway.
+ *
+ * - Unregistering relation is not a cheap operation, so better to have it
+ * as an explicit call if we need this.
+ */
+ from->outlinks.push_back(this);
+ to->inlinks.push_back(this);
}
DepsRelation::~DepsRelation()
{
/* Sanity check. */
BLI_assert(this->from && this->to);
- /* Remove it from the nodes that use it. */
- this->from->outlinks.erase(this);
- this->to->inlinks.erase(this);
}
/* Low level tagging -------------------------------------- */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index a62b23bde68..877ce6e52e9 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -244,17 +244,21 @@ static void deg_graph_build_finalize(Depsgraph *graph)
id_node->layers |= id_to->layers;
}
}
-
- /* Re-tag ID for update if it was tagged before the relations
- * update tag.
- */
- ID *id = id_node->id;
- if (id->tag & LIB_TAG_ID_RECALC_ALL &&
- id->tag & LIB_TAG_DOIT)
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
+ }
+ }
+
+ /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ ID *id = id_node->id;
+ if (id->tag & LIB_TAG_ID_RECALC_ALL &&
+ id->tag & LIB_TAG_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
index 0a5235a6d11..be706ffb338 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -248,6 +248,13 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
* needed.
*/
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are not included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree)
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
+ } FOREACH_NODETREE_END
/* scene ID block */
add_id_node(&scene->id);
@@ -778,6 +785,14 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
}
}
+ /* speed optimization for animation lookups */
+ if (ob->pose) {
+ BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+ }
+
/* Make sure pose is up-to-date with armature updates. */
add_operation_node(&arm->id,
DEPSNODE_TYPE_PARAMETERS,
@@ -872,6 +887,14 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
ID *obdata = (ID *)ob->data;
build_animdata(obdata);
+ BLI_assert(ob->pose != NULL);
+
+ /* speed optimization for animation lookups */
+ BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+
add_operation_node(&ob->id,
DEPSNODE_TYPE_EVAL_POSE,
DEPSOP_TYPE_INIT,
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
index 226991e7b11..52af483d87c 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -244,6 +244,13 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
* created or not.
*/
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are not included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree)
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
+ } FOREACH_NODETREE_END
if (scene->set) {
// TODO: link set to scene, especially our timesource...
@@ -1683,7 +1690,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (mom != ob) {
/* non-motherball -> cannot be directly evaluated! */
ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ add_relation(transform_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
}
break;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index e8065766332..66535f5214b 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -56,6 +56,9 @@ extern "C" {
static bool use_legacy_depsgraph = true;
#endif
+/* Unfinished and unused, and takes quite some pre-processing time. */
+#undef USE_EVAL_PRIORITY
+
bool DEG_depsgraph_use_legacy(void)
{
#ifdef DISABLE_NEW_DEPSGRAPH
@@ -122,7 +125,8 @@ void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const int layers);
+ const int layers,
+ const int thread_id);
struct DepsgraphEvalState {
EvaluationContext *eval_ctx;
@@ -132,75 +136,159 @@ struct DepsgraphEvalState {
static void deg_task_run_func(TaskPool *pool,
void *taskdata,
- int UNUSED(threadid))
+ int thread_id)
{
DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
OperationDepsNode *node = (OperationDepsNode *)taskdata;
- if (!node->is_noop()) {
+ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ while (true) {
/* Get context. */
// TODO: who initialises this? "Init" operations aren't able to initialise it!!!
- /* TODO(sergey): Wedon't use component contexts at this moment. */
+ /* TODO(sergey): We don't use component contexts at this moment. */
/* ComponentDepsNode *comp = node->owner; */
BLI_assert(node->owner != NULL);
- /* Take note of current time. */
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
-
- /* Should only be the case for NOOPs, which never get to this point. */
- BLI_assert(node->evaluate);
-
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
+ /* Take note of current time. */
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+ }
- /* Note how long this took. */
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
+ /* If there's only one outgoing link we try to immediately switch to
+ * that node evaluation, without leaving the thread.
+ *
+ * It's only doable if the child don't have extra relations or all they
+ * are satisfied.
+ *
+ * TODO(sergey): Checks here can be de-duplicated with the ones from
+ * schedule_node(), however, how to do it nicely?
+ */
+ if (node->outlinks.size() == 1) {
+ DepsRelation *rel = node->outlinks[0];
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (!child->scheduled) {
+ int id_layers = child->owner->owner->layers;
+ if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & state->layers) != 0))
+ {
+ /* Node does not need an update, so can;t continue with the
+ * chain and need to switch to another one by leaving the
+ * thread.
+ */
+ break;
+ }
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+ if (child->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&child->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ /* Node was not scheduled, switch to it! */
+ node = child;
+ }
+ else {
+ /* Someone else scheduled the node, leaving us
+ * unemployed in this thread, we're leaving.
+ */
+ break;
+ }
+ }
+ else {
+ /* There are other dependencies on the child, can't do
+ * anything in the current thread.
+ */
+ break;
+ }
+ }
+ else {
+ /* Happens when having cyclic dependencies.
+ *
+ * Nothing to do here, single child was already scheduled, we
+ * can leave the thread now.
+ */
+ break;
+ }
+ }
+ else {
+ /* TODO(sergey): It's possible to use one of the outgoing relations
+ * as a chain which we'll try to keep alive, but it's a bit more
+ * involved change.
+ */
+ schedule_children(pool, state->graph, node, state->layers, thread_id);
+ break;
+ }
}
-
- schedule_children(pool, state->graph, node, state->layers);
}
-static void calculate_pending_parents(Depsgraph *graph, int layers)
+typedef struct CalculatePengindData {
+ Depsgraph *graph;
+ int layers;
+} CalculatePengindData;
+
+static void calculate_pending_func(void *data_v, int i)
{
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
+ CalculatePengindData *data = (CalculatePengindData *)data_v;
+ Depsgraph *graph = data->graph;
+ int layers = data->layers;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
- OperationDepsNode *node = *it_op;
- IDDepsNode *id_node = node->owner->owner;
-
- node->num_links_pending = 0;
- node->scheduled = false;
-
- /* count number of inputs that need updates */
- if ((id_node->layers & layers) != 0 &&
- (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
{
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
{
- DepsRelation *rel = *it_rel;
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
{
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- IDDepsNode *id_from_node = from->owner->owner;
- if ((id_from_node->layers & layers) != 0 &&
- (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- ++node->num_links_pending;
- }
+ ++node->num_links_pending;
}
}
}
+ DEPSNODE_RELATIONS_ITER_END;
}
}
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ CalculatePengindData data;
+ data.graph = graph;
+ data.layers = layers;
+ BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, do_threads);
+}
+
+#ifdef USE_EVAL_PRIORITY
static void calculate_eval_priority(OperationDepsNode *node)
{
if (node->done) {
@@ -229,68 +317,77 @@ static void calculate_eval_priority(OperationDepsNode *node)
node->eval_priority = 0.0f;
}
}
+#endif
+
+/* Schedule a node if it needs evaluation.
+ * dec_parents: Decrement pending parents count, true when child nodes are scheduled
+ * after a task has been completed.
+ */
+static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
+ OperationDepsNode *node, bool dec_parents,
+ const int thread_id)
+{
+ int id_layers = node->owner->owner->layers;
+
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & layers) != 0)
+ {
+ if (dec_parents) {
+ BLI_assert(node->num_links_pending > 0);
+ atomic_sub_uint32(&node->num_links_pending, 1);
+ }
+
+ if (node->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ if (node->is_noop()) {
+ /* skip NOOP node, schedule children right away */
+ schedule_children(pool, graph, node, layers, thread_id);
+ }
+ else {
+ /* children are scheduled once this task is completed */
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_LOW,
+ thread_id);
+ }
+ }
+ }
+ }
+}
static void schedule_graph(TaskPool *pool,
Depsgraph *graph,
const int layers)
{
- BLI_spin_lock(&graph->lock);
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
{
OperationDepsNode *node = *it;
- IDDepsNode *id_node = node->owner->owner;
- if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) &&
- node->num_links_pending == 0 &&
- (id_node->layers & layers) != 0)
- {
- BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
- node->scheduled = true;
- }
+ schedule_node(pool, graph, layers, node, false, 0);
}
- BLI_spin_unlock(&graph->lock);
}
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const int layers)
+ const int layers,
+ const int thread_id)
{
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
{
- DepsRelation *rel = *it;
OperationDepsNode *child = (OperationDepsNode *)rel->to;
BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
-
if (child->scheduled) {
/* Happens when having cyclic dependencies. */
continue;
}
-
- IDDepsNode *id_child = child->owner->owner;
- if ((id_child->layers & layers) != 0 &&
- (child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
- }
-
- if (child->num_links_pending == 0) {
- BLI_spin_lock(&graph->lock);
- bool need_schedule = !child->scheduled;
- child->scheduled = true;
- BLI_spin_unlock(&graph->lock);
-
- if (need_schedule) {
- BLI_task_pool_push(pool, deg_task_run_func, child, false, TASK_PRIORITY_LOW);
- }
- }
- }
+ schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id);
}
+ DEPSNODE_RELATIONS_ITER_END;
}
/**
@@ -341,6 +438,7 @@ void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
}
/* Calculate priority for operation nodes. */
+#ifdef USE_EVAL_PRIORITY
for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
it != graph->operations.end();
++it)
@@ -348,6 +446,7 @@ void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
OperationDepsNode *node = *it;
calculate_eval_priority(node);
}
+#endif
DepsgraphDebug::eval_begin(eval_ctx);
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 486526ed46c..3ca23965749 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -42,6 +42,8 @@ extern "C" {
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_task.h"
+
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -263,6 +265,19 @@ void DEG_id_type_tag(Main *bmain, short idtype)
/* XXX This may get a dedicated implementation later if needed - lukas */
typedef std::queue<OperationDepsNode *> FlushQueue;
+static void flush_init_func(void *data_v, int i)
+{
+ /* ID node's done flag is used to avoid multiple editors update
+ * for the same ID.
+ */
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->done = 0;
+ node->scheduled = false;
+ node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
+}
+
/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
{
@@ -278,14 +293,9 @@ void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
/* TODO(sergey): With a bit of flag magic we can get rid of this
* extra loop.
*/
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- node->scheduled = false;
- node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
- }
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0, num_operations, graph, flush_init_func, do_threads);
FlushQueue queue;
/* Starting from the tagged "entry" nodes, flush outwards... */
@@ -301,7 +311,10 @@ void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
OperationDepsNode *node = *it;
IDDepsNode *id_node = node->owner->owner;
queue.push(node);
- deg_editors_id_update(bmain, id_node->id);
+ if (id_node->done == 0) {
+ deg_editors_id_update(bmain, id_node->id);
+ id_node->done = 1;
+ }
node->scheduled = true;
}
@@ -346,7 +359,10 @@ void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
queue.push(to_node);
to_node->scheduled = true;
- deg_editors_id_update(bmain, id_node->id);
+ if (id_node->done == 0) {
+ deg_editors_id_update(bmain, id_node->id);
+ id_node->done = 1;
+ }
}
}
@@ -384,23 +400,21 @@ void DEG_ids_flush_tagged(Main *bmain)
}
}
+static void graph_clear_func(void *data_v, int i)
+{
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+}
+
/* Clear tags from all operation nodes. */
void DEG_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
-
- /* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
- /* Reset so that it can be bumped up again. */
- node->num_links_pending = 0;
- node->scheduled = false;
- }
-
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
/* Clear any entry tags which haven't been flushed. */
graph->entry_tags.clear();
}
@@ -436,12 +450,11 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
* This is mainly needed on file load only, after that updates of invisible objects
* will be stored in the pending list.
*/
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
++it)
{
- OperationDepsNode *node = *it;
- IDDepsNode *id_node = node->owner->owner;
+ IDDepsNode *id_node = it->second;
ID *id = id_node->id;
if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/depsnode.cc
index 7d4d6890c83..8aa1059d2dc 100644
--- a/source/blender/depsgraph/intern/depsnode.cc
+++ b/source/blender/depsgraph/intern/depsnode.cc
@@ -71,21 +71,16 @@ DepsNode::DepsNode()
DepsNode::~DepsNode()
{
- /* free links
- * note: deleting relations will remove them from the node relations set,
- * but only touch the same position as we are using here, which is safe.
+ /* Free links. */
+ /* NOTE: We only free incoming links. This is to avoid double-free of links
+ * when we're trying to free same link from both it's sides. We don't have
+ * dangling links so this is not a problem from memory leaks point of view.
*/
DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
{
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
DEPSNODE_RELATIONS_ITER_END;
-
- DEPSNODE_RELATIONS_ITER_BEGIN(this->outlinks, rel)
- {
- OBJECT_GUARDED_DELETE(rel, DepsRelation);
- }
- DEPSNODE_RELATIONS_ITER_END;
}
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/depsnode.h
index 53826ae8e71..4a464955384 100644
--- a/source/blender/depsgraph/intern/depsnode.h
+++ b/source/blender/depsgraph/intern/depsnode.h
@@ -73,7 +73,7 @@ struct DepsNode {
* from basic serialization benefits - from the typeinfo) is that we can have
* relationships between these nodes!
*/
- typedef unordered_set<DepsRelation *> Relations;
+ typedef vector<DepsRelation *> Relations;
/* Nodes which this one depends on. */
Relations inlinks;
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 473b0e6bc5a..1bf1bb2a474 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -59,6 +59,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_PYTHON)
+ add_definitions(-DWITH_PYTHON)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 9d54fd8f730..ea2f7fc5588 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3818,6 +3818,9 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
/* send notifiers before doing anything else... */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ if (ale_setting->type == ANIMTYPE_GPLAYER)
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+
/* verify animation context */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 40376c38c3b..823cde75334 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -39,6 +39,8 @@
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
@@ -685,7 +687,7 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
MarkerMove *mm = op->customdata;
TimeMarker *marker, *selmarker = NULL;
const int offs = RNA_int_get(op->ptr, "frames");
- char str[256];
+ char str[UI_MAX_DRAW_STR];
char str_offs[NUM_STR_REP_LEN];
int totmark;
const bool use_time = ed_marker_move_use_time(mm);
@@ -710,14 +712,14 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
if (totmark == 1 && selmarker) {
/* we print current marker value */
if (use_time) {
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %s", FRA2TIME(selmarker->frame), str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs);
}
else {
- BLI_snprintf(str, sizeof(str), "Marker %d offset %s", selmarker->frame, str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker %d offset %s"), selmarker->frame, str_offs);
}
}
else {
- BLI_snprintf(str, sizeof(str), "Marker offset %s", str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs);
}
ED_area_headerprint(CTX_wm_area(C), str);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index f75f2ce322c..afc4e5c9e61 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -61,9 +61,6 @@
#include "anim_intern.h"
-/* called by WM */
-void free_anim_drivers_copybuf(void);
-
/* ************************************************** */
/* Animation Data Validation */
@@ -514,8 +511,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports), ID *id, const char rna_path
static FCurve *channeldriver_copypaste_buf = NULL;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
-// XXX find some header to put this in!
-void free_anim_drivers_copybuf(void)
+void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
if (channeldriver_copypaste_buf)
@@ -553,7 +549,7 @@ bool ANIM_copy_driver(ReportList *reports, ID *id, const char rna_path[], int ar
fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
- free_anim_drivers_copybuf();
+ ANIM_drivers_copybuf_free();
/* copy this to the copy/paste buf if it exists */
if (fcu && fcu->driver) {
@@ -604,7 +600,7 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
/* create Driver F-Curve, but without data which will be copied across... */
fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
-
+
if (fcu) {
/* copy across the curve data from the buffer curve
* NOTE: this step needs care to not miss new settings
@@ -629,6 +625,117 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
}
/* ************************************************** */
+/* Driver Management API - Copy/Paste Driver Variables */
+
+/* Copy/Paste Buffer for Driver Variables... */
+static ListBase driver_vars_copybuf = {NULL, NULL};
+
+/* This function frees any MEM_calloc'ed copy/paste buffer data */
+void ANIM_driver_vars_copybuf_free(void)
+{
+ /* Free the driver variables kept in the buffer */
+ if (driver_vars_copybuf.first) {
+ DriverVar *dvar, *dvarn;
+
+ /* Free variables (and any data they use) */
+ for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable(&driver_vars_copybuf, dvar);
+ }
+ }
+
+ BLI_listbase_clear(&driver_vars_copybuf);
+}
+
+/* Checks if there are driver variables in the copy/paste buffer */
+bool ANIM_driver_vars_can_paste(void)
+{
+ return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
+}
+
+/* -------------------------------------------------- */
+
+/* Copy the given driver's variables to the buffer */
+bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
+{
+ /* sanity checks */
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ BKE_report(reports, RPT_ERROR, "No driver to copy variables from");
+ return false;
+ }
+
+ if (BLI_listbase_is_empty(&fcu->driver->variables)) {
+ BKE_report(reports, RPT_ERROR, "Driver has no variables to copy");
+ return false;
+ }
+
+ /* clear buffer */
+ ANIM_driver_vars_copybuf_free();
+
+ /* copy over the variables */
+ driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables);
+
+ return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
+}
+
+/* Paste the variables in the buffer to the given FCurve */
+bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
+{
+ ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
+ ListBase tmp_list = {NULL, NULL};
+
+ /* sanity checks */
+ if (BLI_listbase_is_empty(&driver_vars_copybuf)) {
+ BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste");
+ return false;
+ }
+
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver");
+ return false;
+ }
+
+ /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */
+ driver_variables_copy(&tmp_list, &driver_vars_copybuf);
+
+ /* 2) Prepare destination array */
+ if (replace) {
+ DriverVar *dvar, *dvarn;
+
+ /* Free all existing vars first - We aren't retaining anything */
+ for (dvar = driver->variables.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable_ex(driver, dvar);
+ }
+
+ BLI_listbase_clear(&driver->variables);
+ }
+
+ /* 3) Add new vars */
+ if (driver->variables.last) {
+ DriverVar *last = driver->variables.last;
+ DriverVar *first = tmp_list.first;
+
+ last->next = first;
+ first->prev = last;
+
+ driver->variables.last = tmp_list.last;
+ }
+ else {
+ driver->variables.first = tmp_list.first;
+ driver->variables.last = tmp_list.last;
+ }
+
+#ifdef WITH_PYTHON
+ /* since driver variables are cached, the expression needs re-compiling too */
+ if (driver->type == DRIVER_TYPE_PYTHON)
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+#endif
+
+ return true;
+}
+
+/* ************************************************** */
/* UI-Button Interface */
/* Add Driver - Enum Defines ------------------------- */
@@ -641,7 +748,8 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
"Drive all components of this property using the target picked"},
{CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
"Drive this component of this property using the target picked"},
- {CREATEDRIVER_MAPPING_N_N, "MATCH", 0, "Match Indices",
+
+ {CREATEDRIVER_MAPPING_N_N, "MATCH", ICON_COLOR, "Match Indices",
"Create drivers for each pair of corresponding elements"},
{CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later",
@@ -778,7 +886,7 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Driver";
ot->idname = "ANIM_OT_driver_button_add";
- ot->description = "Add driver(s) for the property(s) connected represented by the highlighted button";
+ ot->description = "Add driver(s) for the property(s) represented by the highlighted button";
/* callbacks */
/* NOTE: No exec, as we need all these to use the current context info
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 91705d63286..6bb73416fec 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -697,14 +697,14 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
/* free the copy/paste buffer */
-void free_fmodifiers_copybuf(void)
+void ANIM_fmodifiers_copybuf_free(void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
+ * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
* - active: only copy the active modifier
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 9733d920b78..1703210f0b6 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -527,8 +527,7 @@ typedef struct tAnimCopybufItem {
/* This function frees any MEM_calloc'ed copy/paste buffer data */
-// XXX find some header to put this in!
-void free_anim_copybuf(void)
+void ANIM_fcurves_copybuf_free(void)
{
tAnimCopybufItem *aci, *acn;
@@ -563,7 +562,7 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
Scene *scene = ac->scene;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* assume that each of these is an F-Curve */
for (ale = anim_data->first; ale; ale = ale->next) {
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 218f215a350..847b45d612c 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -83,6 +83,15 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
bone->segments = 1;
bone->layer = arm->layer;
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
return bone;
}
@@ -291,12 +300,8 @@ void preEditBoneDuplicate(ListBase *editbones)
/**
* Helper function for #postEditBoneDuplicate,
* return the destination pchan from the original.
- *
- * \param use_orig_fallback: return the input value if no new channel is found.
*/
-static bPoseChannel *pchan_duplicate_map(
- const bPose *pose, GHash *name_map,
- bPoseChannel *pchan_src, bool use_orig_fallback)
+static bPoseChannel *pchan_duplicate_map(const bPose *pose, GHash *name_map, bPoseChannel *pchan_src)
{
bPoseChannel *pchan_dst = NULL;
const char *name_src = pchan_src->name;
@@ -305,7 +310,7 @@ static bPoseChannel *pchan_duplicate_map(
pchan_dst = BKE_pose_channel_find_name(pose, name_dst);
}
- if ((pchan_dst == NULL) && use_orig_fallback) {
+ if (pchan_dst == NULL) {
pchan_dst = pchan_src;
}
@@ -325,6 +330,9 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (!ebone_dst) {
+ ebone_dst = ED_armature_bone_get_mirrored(editbones, ebone_src);
+ }
if (ebone_dst) {
BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
}
@@ -338,7 +346,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
if (pchan_dst) {
if (pchan_src->custom_tx) {
- pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx, true);
+ pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
}
}
}
@@ -682,7 +690,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Run though the list and fix the pointers */
+ /* Run through the list and fix the pointers */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
if (ebone_iter->temp.ebone) {
/* copy all flags except for ... */
@@ -891,6 +899,16 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
newbone->segments = 1;
newbone->layer = ebone->layer;
+ newbone->roll1 = ebone->roll1;
+ newbone->roll2 = ebone->roll2;
+ newbone->curveInX = ebone->curveInX;
+ newbone->curveInY = ebone->curveInY;
+ newbone->curveOutX = ebone->curveOutX;
+ newbone->curveOutY = ebone->curveOutY;
+ newbone->scaleIn = ebone->scaleIn;
+ newbone->scaleOut = ebone->scaleOut;
+
+
BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
if (flipbone && forked) { // only set if mirror edit
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index ac150b9af74..02aefce3464 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -170,6 +170,11 @@ typedef struct tPChanFCurveLink {
float oldangle;
float oldaxis[3];
+ float roll1, roll2; /* old bbone values (to be restored along with the transform properties) */
+ float curveInX, curveInY; /* (NOTE: we haven't renamed these this time, as their names are already long enough) */
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */
} tPChanFCurveLink;
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 61ed7fdc41b..d73536e5ba7 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -179,7 +179,6 @@ EditBone *ED_armature_bone_find_shared_parent(EditBone *ebone_child[], const uns
/* accumulate */
for (i = 0; i < ebone_child_tot; i++) {
- ebone_iter = ebone_child[i];
for (ebone_iter = ebone_child[i]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
EBONE_TEMP_UINT(ebone_iter) += 1;
}
@@ -457,7 +456,16 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
eBone->rad_tail = curBone->rad_tail;
eBone->segments = curBone->segments;
eBone->layer = curBone->layer;
-
+
+ eBone->roll1 = curBone->roll1;
+ eBone->roll2 = curBone->roll2;
+ eBone->curveInX = curBone->curveInX;
+ eBone->curveInY = curBone->curveInY;
+ eBone->curveOutX = curBone->curveOutX;
+ eBone->curveOutY = curBone->curveOutY;
+ eBone->scaleIn = curBone->scaleIn;
+ eBone->scaleOut = curBone->scaleOut;
+
if (curBone->prop)
eBone->prop = IDP_CopyProperty(curBone->prop);
@@ -612,7 +620,17 @@ void ED_armature_from_edit(bArmature *arm)
newBone->rad_tail = eBone->rad_tail;
newBone->segments = eBone->segments;
newBone->layer = eBone->layer;
-
+
+ newBone->roll1 = eBone->roll1;
+ newBone->roll2 = eBone->roll2;
+ newBone->curveInX = eBone->curveInX;
+ newBone->curveInY = eBone->curveInY;
+ newBone->curveOutX = eBone->curveOutX;
+ newBone->curveOutY = eBone->curveOutY;
+ newBone->scaleIn = eBone->scaleIn;
+ newBone->scaleOut = eBone->scaleOut;
+
+
if (eBone->prop)
newBone->prop = IDP_CopyProperty(eBone->prop);
}
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 7c09ad49f35..fa7bf6e7ad4 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -1451,6 +1451,15 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
bone->segments = 1;
bone->layer = 1; //arm->layer;
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
return bone;
}
#endif
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 87d75aa8fad..5530e293edd 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -47,6 +47,7 @@
#include "BIF_generate.h"
#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -969,100 +970,30 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
ToolSettings *ts = CTX_data_tool_settings(C);
int point_added = 0;
- if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
- DepthPeel *p1, *p2;
- float *last_p = NULL;
- float dist = FLT_MAX;
- float p[3] = {0};
- float size = 0;
- float mvalf[2];
-
- BLI_freelistN(&sketch->depth_peels);
- BLI_listbase_clear(&sketch->depth_peels);
-
- mvalf[0] = dd->mval[0];
- mvalf[1] = dd->mval[1];
- peelObjectsContext(C, mvalf, SNAP_ALL, &sketch->depth_peels);
-
- if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) {
- last_p = stk->points[stk->nb_points - 1].p;
- }
- else if (LAST_SNAP_POINT_VALID) {
- last_p = LAST_SNAP_POINT;
- }
-
-
- for (p1 = sketch->depth_peels.first; p1; p1 = p1->next) {
- if (p1->flag == 0) {
- float vec[3];
- float new_dist;
- float new_size = 0;
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), 0,
+ CTX_wm_region(C), CTX_wm_view3d(C));
- p2 = NULL;
- p1->flag = 1;
+ float mvalf[2] = {UNPACK2(dd->mval)};
+ float loc[3], dummy_no[3];
- /* if peeling objects, take the first and last from each object */
- if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) {
- DepthPeel *peel;
- for (peel = p1->next; peel; peel = peel->next) {
- if (peel->ob == p1->ob) {
- peel->flag = 1;
- p2 = peel;
- }
- }
- }
- /* otherwise, pair first with second and so on */
- else {
- for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) {
- /* nothing to do here */
- }
- }
-
- if (p2) {
- p2->flag = 1;
-
- add_v3_v3v3(vec, p1->p, p2->p);
- mul_v3_fl(vec, 0.5f);
- new_size = len_v3v3(p1->p, p2->p);
- }
- else {
- copy_v3_v3(vec, p1->p);
- }
-
- if (last_p == NULL) {
- copy_v3_v3(p, vec);
- size = new_size;
- dist = 0;
- break;
- }
-
- new_dist = len_v3v3(last_p, vec);
-
- if (new_dist < dist) {
- copy_v3_v3(p, vec);
- dist = new_dist;
- size = new_size;
- }
- }
- }
-
- if (dist != FLT_MAX) {
+ if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
+ float size;
+ if (peelObjectsSnapContext(
+ snap_context, mvalf, SNAP_ALL,
+ (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
+ loc, dummy_no, &size))
+ {
pt->type = dd->type;
pt->mode = PT_SNAP;
pt->size = size / 2;
- copy_v3_v3(pt->p, p);
+ copy_v3_v3(pt->p, loc);
point_added = 1;
}
-
- //BLI_freelistN(&depth_peels);
}
else {
SK_Stroke *snap_stk;
- float vec[3];
- float no[3];
- float mval[2];
- int found = 0;
float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
/* snap to strokes */
@@ -1081,23 +1012,28 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
point_added = 1;
}
}
-
- mval[0] = dd->mval[0];
- mval[1] = dd->mval[1];
/* try to snap to closer object */
- found = snapObjectsContext(
- C, mval, SNAP_NOT_SELECTED,
- vec, no, &dist_px);
- if (found == 1) {
- pt->type = dd->type;
- pt->mode = PT_SNAP;
- copy_v3_v3(pt->p, vec);
+ {
+ if (ED_transform_snap_object_project_view3d(
+ snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_SELECTED,
+ .snap_to = ts->snap_mode,
+ },
+ mvalf, &dist_px, NULL,
+ loc, dummy_no))
+ {
+ pt->type = dd->type;
+ pt->mode = PT_SNAP;
+ copy_v3_v3(pt->p, loc);
- point_added = 1;
+ point_added = 1;
+ }
}
}
+ ED_transform_snap_object_context_destroy(snap_context);
return point_added;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index a984e5d1ccd..dca9aa3e446 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -762,7 +762,7 @@ typedef struct tPoseLib_PreviewData {
char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */
char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */
- char headerstr[200]; /* Info-text to print in header */
+ char headerstr[UI_MAX_DRAW_STR]; /* Info-text to print in header */
} tPoseLib_PreviewData;
/* defines for tPoseLib_PreviewData->state values */
@@ -1016,7 +1016,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
BLI_strncpy(pld->headerstr,
- "PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again",
+ IFACE_("PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"),
sizeof(pld->headerstr));
ED_area_headerprint(pld->sa, pld->headerstr);
}
@@ -1041,16 +1041,16 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern));
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- "PoseLib Previewing Pose: Filter - [%s] | "
- "Current Pose - \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change",
+ IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
+ "Current Pose - \"%s\" | "
+ "Use ScrollWheel or PageUp/Down to change"),
tempstr, markern);
ED_area_headerprint(pld->sa, pld->headerstr);
}
else {
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- "PoseLib Previewing Pose: \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change",
+ IFACE_("PoseLib Previewing Pose: \"%s\" | "
+ "Use ScrollWheel or PageUp/Down to change"),
pld->marker->name);
ED_area_headerprint(pld->sa, pld->headerstr);
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 16ba1483e38..cd0ea23e2d3 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -51,6 +51,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
@@ -301,8 +303,8 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
MEM_freeN(path);
}
-/* helper for apply() - perform sliding for custom properties */
-static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
+/* helper for apply() - perform sliding for custom properties or bbone properties */
+static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
{
PointerRNA ptr = {{NULL}};
LinkData *ld;
@@ -311,8 +313,10 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* setup pointer RNA for resolving paths */
RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
- /* custom properties are just denoted using ["..."][etc.] after the end of the base path,
- * so just check for opening pair after the end of the path
+ /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
+ * so just check for opening pair after the end of the path
+ * - bbone properties are similar, but they always start with a prefix "bbone_*",
+ * so a similar method should work here for those too
*/
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
@@ -326,7 +330,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
* - pPtr is the chunk of the path which is left over
*/
bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
- pPtr = strstr(bPtr, "[\""); /* dummy " for texteditor bugs */
+ pPtr = strstr(bPtr, prop_prefix);
if (pPtr) {
/* use RNA to try and get a handle on this property, then, assuming that it is just
@@ -515,9 +519,16 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
+ if (pchan->flag & POSE_BBONE_SHAPE) {
+ /* bbone properties - they all start a "bbone_" prefix */
+ pose_slide_apply_props(pso, pfl, "bbone_");
+ }
+
if (pfl->oldprops) {
- /* not strictly a transform, but contributes to the pose produced in many rigs */
- pose_slide_apply_props(pso, pfl);
+ /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
+ * (e.g. the facial rigs used in Sintel)
+ */
+ pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
}
}
@@ -544,7 +555,7 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* draw percentage indicator in header */
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[256];
+ char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
switch (pso->mode) {
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 01e16df9f08..df906a3638a 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -367,10 +367,26 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
}
+ /* B-Bone posing options should also be included... */
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
/* paste flipped pose? */
if (flip) {
pchan->loc[0] *= -1;
+ pchan->curveInX *= -1;
+ pchan->curveOutX *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
+
/* has to be done as eulers... */
if (pchan->rotmode > 0) {
pchan->eul[1] *= -1;
@@ -540,6 +556,9 @@ static void pchan_clear_scale(bPoseChannel *pchan)
pchan->size[1] = 1.0f;
if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
pchan->size[2] = 1.0f;
+
+ pchan->scaleIn = 1.0f;
+ pchan->scaleOut = 1.0f;
}
/* clear location of pose-channel */
@@ -650,6 +669,15 @@ static void pchan_clear_rot(bPoseChannel *pchan)
zero_v3(pchan->eul);
}
}
+
+ /* Clear also Bendy Bone stuff - Roll is obvious, but Curve X/Y stuff is also kindof rotational in nature... */
+ pchan->roll1 = 0.0f;
+ pchan->roll2 = 0.0f;
+
+ pchan->curveInX = 0.0f;
+ pchan->curveInY = 0.0f;
+ pchan->curveOutX = 0.0f;
+ pchan->curveOutY = 0.0f;
}
/* clear loc/rot/scale of pose-channel */
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 2ba1eedd33b..b960bec3603 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -71,7 +71,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
ListBase curves = {NULL, NULL};
int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
/* check if any transforms found... */
if (transFlags) {
@@ -96,6 +96,8 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
pchan->flag |= POSE_ROT;
if (transFlags & ACT_TRANS_SCALE)
pchan->flag |= POSE_SIZE;
+ if (transFlags & ACT_TRANS_BBONE)
+ pchan->flag |= POSE_BBONE_SHAPE;
/* store current transforms */
copy_v3_v3(pfl->oldloc, pchan->loc);
@@ -105,6 +107,16 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
pfl->oldangle = pchan->rotAngle;
+ /* store current bbone values */
+ pfl->roll1 = pchan->roll1;
+ pfl->roll2 = pchan->roll2;
+ pfl->curveInX = pchan->curveInX;
+ pfl->curveInY = pchan->curveInY;
+ pfl->curveOutX = pchan->curveOutX;
+ pfl->curveOutY = pchan->curveOutY;
+ pfl->scaleIn = pchan->scaleIn;
+ pfl->scaleOut = pchan->scaleOut;
+
/* make copy of custom properties */
if (pchan->prop && (transFlags & ACT_TRANS_PROP))
pfl->oldprops = IDP_CopyProperty(pchan->prop);
@@ -133,6 +145,7 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a
fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
}
CTX_DATA_END;
+
}
}
@@ -199,6 +212,16 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
pchan->rotAngle = pfl->oldangle;
+ /* store current bbone values */
+ pchan->roll1 = pfl->roll1;
+ pchan->roll2 = pfl->roll2;
+ pchan->curveInX = pfl->curveInX;
+ pchan->curveInY = pfl->curveInY;
+ pchan->curveOutX = pfl->curveOutX;
+ pchan->curveOutY = pfl->curveOutY;
+ pchan->scaleIn = pfl->scaleIn;
+ pchan->scaleOut = pfl->scaleOut;
+
/* just overwrite values of properties from the stored copies (there should be some) */
if (pfl->oldprops)
IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 83346e9550c..ebdf6bb43ff 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,20 +23,24 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
+ ../../../../extern/curve_fit_nd
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
curve_ops.c
editcurve.c
editcurve_add.c
+ editcurve_paint.c
editcurve_select.c
editfont.c
@@ -47,4 +51,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_curve "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 1af0b49bd86..856573ffab0 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -102,6 +102,7 @@ void CURVE_OT_separate(struct wmOperatorType *ot);
void CURVE_OT_split(struct wmOperatorType *ot);
void CURVE_OT_duplicate(struct wmOperatorType *ot);
void CURVE_OT_delete(struct wmOperatorType *ot);
+void CURVE_OT_dissolve_verts(struct wmOperatorType *ot);
void CURVE_OT_spline_type_set(struct wmOperatorType *ot);
void CURVE_OT_radius_set(struct wmOperatorType *ot);
@@ -166,4 +167,7 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot);
+/* editcurve_paint.c */
+void CURVE_OT_draw(struct wmOperatorType *ot);
+
#endif /* __CURVE_INTERN_H__ */
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 967187e66c9..fce6425b9be 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -87,6 +87,7 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(CURVE_OT_split);
WM_operatortype_append(CURVE_OT_duplicate);
WM_operatortype_append(CURVE_OT_delete);
+ WM_operatortype_append(CURVE_OT_dissolve_verts);
WM_operatortype_append(CURVE_OT_spline_type_set);
WM_operatortype_append(CURVE_OT_radius_set);
@@ -135,6 +136,7 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(CURVE_OT_make_segment);
WM_operatortype_append(CURVE_OT_spin);
WM_operatortype_append(CURVE_OT_vertex_add);
+ WM_operatortype_append(CURVE_OT_draw);
WM_operatortype_append(CURVE_OT_extrude);
WM_operatortype_append(CURVE_OT_cyclic_toggle);
@@ -234,6 +236,9 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CURVE_OT_vertex_add", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
@@ -258,8 +263,12 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "CURVE_OT_cyclic_toggle", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_delete", DELKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", DELKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", XKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", DELKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "CURVE_OT_tilt_clear", TKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "TRANSFORM_OT_tilt", TKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 77fc7a83256..18fdcb546b0 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_ghash.h"
@@ -63,6 +64,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
#include "ED_util.h"
#include "ED_view3d.h"
@@ -70,6 +72,8 @@
#include "curve_intern.h"
+#include "curve_fit_nd.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -1390,7 +1394,9 @@ void CURVE_OT_split(wmOperatorType *ot)
/* ******************* FLAGS ********************* */
-static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
+static bool isNurbselUV(
+ const Nurb *nu, int flag,
+ int *r_u, int *r_v)
{
/* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
* return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
@@ -1398,7 +1404,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
BPoint *bp;
int a, b, sel;
- *u = *v = -1;
+ *r_u = *r_v = -1;
bp = nu->bp;
for (b = 0; b < nu->pntsv; b++) {
@@ -1407,7 +1413,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (bp->f1 & flag) sel++;
}
if (sel == nu->pntsu) {
- if (*u == -1) *u = b;
+ if (*r_u == -1) *r_u = b;
else return 0;
}
else if (sel > 1) {
@@ -1422,7 +1428,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (bp->f1 & flag) sel++;
}
if (sel == nu->pntsv) {
- if (*v == -1) *v = a;
+ if (*r_v == -1) *r_v = a;
else return 0;
}
else if (sel > 1) {
@@ -1430,8 +1436,8 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
}
}
- if (*u == -1 && *v > -1) return 1;
- if (*v == -1 && *u > -1) return 1;
+ if (*r_u == -1 && *r_v > -1) return 1;
+ if (*r_v == -1 && *r_u > -1) return 1;
return 0;
}
@@ -1851,7 +1857,7 @@ bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
else {
/* which row or column is selected */
- if (isNurbselUV(nu, &u, &v, flag)) {
+ if (isNurbselUV(nu, flag, &u, &v)) {
/* deselect all */
bp = nu->bp;
@@ -4991,11 +4997,22 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_proj) {
const float mval[2] = {UNPACK2(event->mval)};
- float no_dummy[3];
- float dist_px_dummy;
- snapObjectsContext(
- C, mval, SNAP_NOT_OBEDIT,
- location, no_dummy, &dist_px_dummy);
+
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), vc.scene, 0,
+ vc.ar, vc.v3d);
+
+ ED_transform_snap_object_project_view3d_mixed(
+ snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_OBEDIT,
+ .snap_to_flag = SCE_SELECT_FACE,
+ },
+ mval, NULL, true,
+ location, NULL);
+
+
+ ED_transform_snap_object_context_destroy(snap_context);
}
if ((cu->flag & CU_3D) == 0) {
@@ -5763,6 +5780,115 @@ void CURVE_OT_delete(wmOperatorType *ot)
ot->prop = prop;
}
+static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
+{
+ Curve *cu = user_data;
+ const BezTriple *bezt = bezt_v;
+ return BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt);
+}
+
+static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = (Curve *)obedit->data;
+
+ {
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if ((nu->type == CU_BEZIER) && (nu->pntsu > 2)) {
+ unsigned int span_step[2] = {nu->pntsu, nu->pntsu};
+ unsigned int span_len;
+
+ while (BLI_array_iter_span(
+ nu->bezt, nu->pntsu,
+ (nu->flagu & CU_NURB_CYCLIC) != 0, false,
+ test_bezt_is_sel_any, cu,
+ span_step, &span_len))
+ {
+ BezTriple *bezt_prev = &nu->bezt[mod_i(span_step[0] - 1, nu->pntsu)];
+ BezTriple *bezt_next = &nu->bezt[mod_i(span_step[1] + 1, nu->pntsu)];
+
+ int i_span_edge_len = span_len + 1;
+ const unsigned int dims = 3;
+
+ const unsigned int points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
+ float *points = MEM_mallocN(points_len * dims * sizeof(float), __func__);
+ float *points_stride = points;
+ const int points_stride_len = (cu->resolu - 1);
+
+ for (int segment = 0; segment < i_span_edge_len; segment++) {
+ BezTriple *bezt_a = &nu->bezt[mod_i((span_step[0] + segment) - 1, nu->pntsu)];
+ BezTriple *bezt_b = &nu->bezt[mod_i((span_step[0] + segment), nu->pntsu)];
+
+ for (int axis = 0; axis < dims; axis++) {
+ BKE_curve_forward_diff_bezier(
+ bezt_a->vec[1][axis], bezt_a->vec[2][axis],
+ bezt_b->vec[0][axis], bezt_b->vec[1][axis],
+ points_stride + axis, points_stride_len, dims * sizeof(float));
+ }
+
+ points_stride += dims * points_stride_len;
+ }
+
+ BLI_assert(points_stride + dims == points + (points_len * dims));
+
+ float tan_l[3], tan_r[3], error_sq_dummy;
+
+ sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
+ normalize_v3(tan_l);
+ sub_v3_v3v3(tan_r, bezt_next->vec[0], bezt_next->vec[1]);
+ normalize_v3(tan_r);
+
+ curve_fit_cubic_to_points_single_fl(
+ points, points_len, dims, FLT_EPSILON,
+ tan_l, tan_r,
+ bezt_prev->vec[2], bezt_next->vec[0],
+ &error_sq_dummy);
+
+ if (!ELEM(bezt_prev->h2, HD_FREE, HD_ALIGN)) {
+ bezt_prev->h2 = (bezt_prev->h2 == HD_VECT) ? HD_FREE : HD_ALIGN;
+ }
+ if (!ELEM(bezt_next->h1, HD_FREE, HD_ALIGN)) {
+ bezt_next->h1 = (bezt_next->h1 == HD_VECT) ? HD_FREE : HD_ALIGN;
+ }
+
+ MEM_freeN(points);
+ }
+ }
+ }
+ }
+
+ ed_curve_delete_selected(obedit);
+
+ {
+ cu->actnu = cu->actvert = CU_ACT_NONE;
+
+ if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_dissolve_verts(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dissolve Vertices";
+ ot->description = "Delete selected control points, correcting surrounding handles";
+ ot->idname = "CURVE_OT_dissolve_verts";
+
+ /* api callbacks */
+ ot->exec = curve_dissolve_exec;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/********************** shade smooth/flat operator *********************/
static int shade_smooth_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
new file mode 100644
index 00000000000..bb7cc61f580
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -0,0 +1,1234 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editcurve_paint.c
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_curve.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "curve_intern.h"
+
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#define USE_SPLINE_FIT
+
+#ifdef USE_SPLINE_FIT
+#include "curve_fit_nd.h"
+#endif
+
+/* Distance between input samples */
+#define STROKE_SAMPLE_DIST_MIN_PX 3
+#define STROKE_SAMPLE_DIST_MAX_PX 6
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Depth Utilities
+ * \{ */
+
+
+static float depth_read_zbuf(const ViewContext *vc, int x, int y)
+{
+ ViewDepths *vd = vc->rv3d->depths;
+
+ if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
+ return vd->depths[y * vd->w + x];
+ else
+ return -1.0f;
+}
+
+static bool depth_unproject(
+ const ARegion *ar, const bglMats *mats,
+ const int mval[2], const double depth,
+ float r_location_world[3])
+{
+ double p[3];
+ if (gluUnProject(
+ (double)ar->winrct.xmin + mval[0] + 0.5,
+ (double)ar->winrct.ymin + mval[1] + 0.5,
+ depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
+ &p[0], &p[1], &p[2]))
+ {
+ copy_v3fl_v3db(r_location_world, p);
+ return true;
+ }
+ return false;
+}
+
+static bool depth_read_normal(
+ const ViewContext *vc, const bglMats *mats, const int mval[2],
+ float r_normal[3])
+{
+ /* pixels surrounding */
+ bool depths_valid[9] = {false};
+ float coords[9][3] = {{0}};
+
+ ARegion *ar = vc->ar;
+ const ViewDepths *depths = vc->rv3d->depths;
+
+ for (int x = 0, i = 0; x < 2; x++) {
+ for (int y = 0; y < 2; y++) {
+ const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
+
+ const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+ depths_valid[i] = true;
+ }
+ }
+ i++;
+ }
+ }
+
+ const int edges[2][6][2] = {
+ /* x edges */
+ {{0, 1}, {1, 2},
+ {3, 4}, {4, 5},
+ {6, 7}, {7, 8}},
+ /* y edges */
+ {{0, 3}, {3, 6},
+ {1, 4}, {4, 7},
+ {2, 5}, {5, 8}},
+ };
+
+ float cross[2][3] = {{0.0f}};
+
+ for (int i = 0; i < 6; i++) {
+ for (int axis = 0; axis < 2; axis++) {
+ if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
+ float delta[3];
+ sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
+ add_v3_v3(cross[axis], delta);
+ }
+ }
+ }
+
+ cross_v3_v3v3(r_normal, cross[0], cross[1]);
+
+ if (normalize_v3(r_normal) != 0.0f) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions
+ * \{ */
+
+struct StrokeElem {
+ float mval[2];
+ float location_world[3];
+ float location_local[3];
+
+ /* surface normal, may be zero'd */
+ float normal_world[3];
+ float normal_local[3];
+
+ float pressure;
+};
+
+struct CurveDrawData {
+ short init_event_type;
+ short curve_type;
+
+ /* projecting 2D into 3D space */
+ struct {
+ /* use a plane or project to the surface */
+ bool use_plane;
+ float plane[4];
+
+ /* use 'rv3d->depths', note that this will become 'damaged' while drawing, but thats OK. */
+ bool use_depth;
+
+ /* offset projection by this value */
+ bool use_offset;
+ float offset[3]; /* worldspace */
+ float surface_offset;
+ bool use_surface_offset_absolute;
+ } project;
+
+ /* cursor sampling */
+ struct {
+ /* use substeps, needed for nicely interpolating depth */
+ bool use_substeps;
+ } sample;
+
+ struct {
+ float min, max, range;
+ } radius;
+
+ struct {
+ float mouse[2];
+ /* used incase we can't calculate the depth */
+ float location_world[3];
+
+ float location_world_valid[3];
+
+ const struct StrokeElem *selem;
+ } prev;
+
+ ViewContext vc;
+ bglMats mats;
+ enum {
+ CURVE_DRAW_IDLE = 0,
+ CURVE_DRAW_PAINTING = 1,
+ } state;
+
+ /* StrokeElem */
+ BLI_mempool *stroke_elem_pool;
+
+ void *draw_handle_view;
+};
+
+static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd, const float pressure)
+{
+ const Curve *cu = cdd->vc.obedit->data;
+ return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
+}
+
+static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
+{
+ return stroke_elem_radius_from_pressure(cdd, selem->pressure);
+}
+
+static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure)
+{
+ if ((cdd->project.surface_offset != 0.0f) &&
+ !cdd->project.use_surface_offset_absolute &&
+ !is_zero_v3(selem->normal_local))
+ {
+ const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) -
+ stroke_elem_radius_from_pressure(cdd, selem->pressure);
+ madd_v3_v3fl(selem->location_local, selem->normal_local, adjust);
+ mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local);
+ }
+ selem->pressure = pressure;
+}
+
+static void stroke_elem_interp(
+ struct StrokeElem *selem_out,
+ const struct StrokeElem *selem_a, const struct StrokeElem *selem_b, float t)
+{
+ interp_v2_v2v2(selem_out->mval, selem_a->mval, selem_b->mval, t);
+ interp_v3_v3v3(selem_out->location_world, selem_a->location_world, selem_b->location_world, t);
+ interp_v3_v3v3(selem_out->location_local, selem_a->location_local, selem_b->location_local, t);
+ selem_out->pressure = interpf(selem_a->pressure, selem_b->pressure, t);
+}
+
+
+/**
+ * Sets the depth from #StrokeElem.mval
+ */
+static bool stroke_elem_project(
+ const struct CurveDrawData *cdd,
+ const int mval_i[2], const float mval_fl[2],
+ float surface_offset, const float radius,
+ float r_location_world[3], float r_normal_world[3])
+{
+ View3D *v3d = cdd->vc.v3d;
+ ARegion *ar = cdd->vc.ar;
+ RegionView3D *rv3d = cdd->vc.rv3d;
+
+ bool is_location_world_set = false;
+
+ /* project to 'location_world' */
+ if (cdd->project.use_plane) {
+ /* get the view vector to 'location' */
+ float ray_origin[3], ray_direction[3];
+ ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false);
+
+ float lambda;
+ if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) {
+ madd_v3_v3v3fl(r_location_world, ray_origin, ray_direction, lambda);
+ if (r_normal_world) {
+ zero_v3(r_normal_world);
+ }
+ is_location_world_set = true;
+ }
+ }
+ else {
+ const ViewDepths *depths = rv3d->depths;
+ if (depths &&
+ ((unsigned int)mval_i[0] < depths->w) &&
+ ((unsigned int)mval_i[1] < depths->h))
+ {
+ const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
+ is_location_world_set = true;
+ if (r_normal_world) {
+ zero_v3(r_normal_world);
+ }
+
+ if (surface_offset != 0.0f) {
+ const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
+ float normal[3];
+ if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
+ madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
+ if (r_normal_world) {
+ copy_v3_v3(r_normal_world, normal);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (is_location_world_set) {
+ if (cdd->project.use_offset) {
+ add_v3_v3(r_location_world, cdd->project.offset);
+ }
+ }
+
+ return is_location_world_set;
+}
+
+static bool stroke_elem_project_fallback(
+ const struct CurveDrawData *cdd,
+ const int mval_i[2], const float mval_fl[2],
+ const float surface_offset, const float radius,
+ const float location_fallback_depth[3],
+ float r_location_world[3], float r_location_local[3],
+ float r_normal_world[3], float r_normal_local[3])
+{
+ bool is_depth_found = stroke_elem_project(
+ cdd, mval_i, mval_fl,
+ surface_offset, radius,
+ r_location_world, r_normal_world);
+ if (is_depth_found == false) {
+ ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
+ zero_v3(r_normal_local);
+ }
+ mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
+
+ if (!is_zero_v3(r_normal_world)) {
+ copy_v3_v3(r_normal_local, r_normal_world);
+ mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local);
+ normalize_v3(r_normal_local);
+ }
+ else {
+ zero_v3(r_normal_local);
+ }
+
+ return is_depth_found;
+}
+
+/**
+ * \note #StrokeElem.mval & #StrokeElem.pressure must be set first.
+ */
+static bool stroke_elem_project_fallback_elem(
+ const struct CurveDrawData *cdd,
+ const float location_fallback_depth[3],
+ struct StrokeElem *selem)
+{
+ const int mval_i[2] = {UNPACK2(selem->mval)};
+ const float radius = stroke_elem_radius(cdd, selem);
+ return stroke_elem_project_fallback(
+ cdd, mval_i, selem->mval,
+ cdd->project.surface_offset, radius,
+ location_fallback_depth,
+ selem->location_world, selem->location_local,
+ selem->normal_world, selem->normal_local);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Operator/Stroke Conversion
+ * \{ */
+
+static void curve_draw_stroke_to_operator_elem(
+ wmOperator *op, const struct StrokeElem *selem)
+{
+ PointerRNA itemptr;
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", selem->mval);
+ RNA_float_set_array(&itemptr, "location", selem->location_world);
+ RNA_float_set(&itemptr, "pressure", selem->pressure);
+}
+
+static void curve_draw_stroke_from_operator_elem(
+ wmOperator *op, PointerRNA *itemptr)
+{
+ struct CurveDrawData *cdd = op->customdata;
+
+ struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
+
+ RNA_float_get_array(itemptr, "mouse", selem->mval);
+ RNA_float_get_array(itemptr, "location", selem->location_world);
+ mul_v3_m4v3(selem->location_local, cdd->vc.obedit->imat, selem->location_world);
+ selem->pressure = RNA_float_get(itemptr, "pressure");
+}
+
+static void curve_draw_stroke_to_operator(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ curve_draw_stroke_to_operator_elem(op, selem);
+ }
+}
+
+static void curve_draw_stroke_from_operator(wmOperator *op)
+{
+ RNA_BEGIN (op->ptr, itemptr, "stroke")
+ {
+ curve_draw_stroke_from_operator_elem(op, &itemptr);
+ }
+ RNA_END;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Operator Callbacks & Helpers
+ * \{ */
+
+static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct CurveDrawData *cdd = op->customdata;
+
+ const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ if (stroke_len == 0) {
+ return;
+ }
+
+ View3D *v3d = cdd->vc.v3d;
+ Object *obedit = cdd->vc.obedit;
+ Curve *cu = obedit->data;
+
+ UI_ThemeColor(TH_WIRE);
+
+ if (cu->ext2 > 0.0f) {
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ const float location_zero[3] = {0};
+ const float *location_prev = location_zero;
+
+ /* scale to edit-mode space */
+ glPushMatrix();
+ glMultMatrixf(obedit->obmat);
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ glTranslatef(
+ selem->location_local[0] - location_prev[0],
+ selem->location_local[1] - location_prev[1],
+ selem->location_local[2] - location_prev[2]);
+ location_prev = selem->location_local;
+ const float radius = stroke_elem_radius(cdd, selem);
+ gluSphere(qobj, radius, 12, 8);
+
+ location_prev = selem->location_local;
+ }
+
+ glPopMatrix();
+
+ gluDeleteQuadric(qobj);
+ }
+
+ if (stroke_len > 1) {
+ float (*coord_array)[3] = MEM_mallocN(sizeof(*coord_array) * stroke_len, __func__);
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+ int i;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter), i = 0; selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ copy_v3_v3(coord_array[i], selem->location_world);
+ }
+ }
+
+ {
+ glEnable(GL_BLEND);
+ glEnable(GL_LINE_SMOOTH);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, coord_array);
+
+ cpack(0x0);
+ glLineWidth(3.0f);
+ glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
+
+ if (v3d->zbuf)
+ glDisable(GL_DEPTH_TEST);
+
+ cpack(0xffffffff);
+ glLineWidth(1.0f);
+ glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
+
+ if (v3d->zbuf)
+ glEnable(GL_DEPTH_TEST);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ MEM_freeN(coord_array);
+ }
+}
+
+static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ Object *obedit = cdd->vc.obedit;
+
+ invert_m4_m4(obedit->imat, obedit->obmat);
+
+ struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
+
+ ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ selem->pressure = wmtab->Pressure;
+ }
+ else {
+ selem->pressure = 1.0f;
+ }
+
+ bool is_depth_found = stroke_elem_project_fallback_elem(
+ cdd, cdd->prev.location_world_valid, selem);
+
+ if (is_depth_found) {
+ /* use the depth if a fallback wasn't used */
+ copy_v3_v3(cdd->prev.location_world_valid, selem->location_world);
+ }
+ copy_v3_v3(cdd->prev.location_world, selem->location_world);
+
+ float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
+ copy_v2_v2(cdd->prev.mouse, selem->mval);
+
+ if (cdd->sample.use_substeps && cdd->prev.selem) {
+ const struct StrokeElem selem_target = *selem;
+ struct StrokeElem *selem_new_last = selem;
+ if (len_sq >= SQUARE(STROKE_SAMPLE_DIST_MAX_PX)) {
+ int n = (int)ceil(sqrt((double)len_sq)) / STROKE_SAMPLE_DIST_MAX_PX ;
+
+ for (int i = 1; i < n; i++) {
+ struct StrokeElem *selem_new = selem_new_last;
+ stroke_elem_interp(selem_new, cdd->prev.selem, &selem_target, (float)i / n);
+
+ const bool is_depth_found_substep = stroke_elem_project_fallback_elem(
+ cdd, cdd->prev.location_world_valid, selem_new);
+ if (is_depth_found == false) {
+ if (is_depth_found_substep) {
+ copy_v3_v3(cdd->prev.location_world_valid, selem_new->location_world);
+ }
+ }
+
+ selem_new_last = BLI_mempool_calloc(cdd->stroke_elem_pool);
+ }
+ }
+ selem = selem_new_last;
+ *selem_new_last = selem_target;
+ }
+
+ cdd->prev.selem = selem;
+
+ ED_region_tag_redraw(cdd->vc.ar);
+}
+
+static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ /* add first point */
+ curve_draw_event_add(op, event);
+
+ if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) && cdd->project.use_depth &&
+ (cps->flag & CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS))
+ {
+ RegionView3D *rv3d = cdd->vc.rv3d;
+
+ cdd->project.use_depth = false;
+ cdd->project.use_plane = true;
+
+ float normal[3] = {0.0f};
+ if (ELEM(cps->surface_plane,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE))
+ {
+ if (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
+ if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
+ float cross_a[3], cross_b[3];
+ cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
+ cross_v3_v3v3(cross_b, normal, cross_a);
+ copy_v3_v3(normal, cross_b);
+ }
+ }
+ }
+
+ /* CURVE_PAINT_SURFACE_PLANE_VIEW or fallback */
+ if (is_zero_v3(normal)) {
+ copy_v3_v3(normal, rv3d->viewinv[2]);
+ }
+
+ normalize_v3_v3(cdd->project.plane, normal);
+ cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, cdd->prev.location_world_valid);
+
+ /* Special case for when we only have offset applied on the first-hit,
+ * the remaining stroke must be offset too. */
+ if (cdd->project.surface_offset != 0.0f) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ float location_no_offset[3];
+
+ if (stroke_elem_project(
+ cdd, event->mval, mval_fl, 0.0f, 0.0f,
+ location_no_offset, NULL))
+ {
+ sub_v3_v3v3(cdd->project.offset, cdd->prev.location_world_valid, location_no_offset);
+ if (!is_zero_v3(cdd->project.offset)) {
+ cdd->project.use_offset = true;
+ }
+ }
+ }
+ /* end special case */
+
+ }
+
+ cdd->init_event_type = event->type;
+ cdd->state = CURVE_DRAW_PAINTING;
+}
+
+static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
+{
+ BLI_assert(op->customdata == NULL);
+
+ struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+
+ if (is_invoke) {
+ view3d_set_viewcontext(C, &cdd->vc);
+ if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
+ MEM_freeN(cdd);
+ BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
+ return false;
+ }
+ }
+ else {
+ cdd->vc.scene = CTX_data_scene(C);
+ cdd->vc.obedit = CTX_data_edit_object(C);
+ }
+
+ op->customdata = cdd;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ cdd->curve_type = cps->curve_type;
+
+ cdd->radius.min = cps->radius_min;
+ cdd->radius.max = cps->radius_max;
+ cdd->radius.range = cps->radius_max - cps->radius_min;
+ cdd->project.surface_offset = cps->surface_offset;
+ cdd->project.use_surface_offset_absolute = (cps->flag & CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS) != 0;
+
+ cdd->stroke_elem_pool = BLI_mempool_create(
+ sizeof(struct StrokeElem), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+ return true;
+}
+
+
+static void curve_draw_exit(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ if (cdd) {
+ if (cdd->draw_handle_view) {
+ ED_region_draw_cb_exit(cdd->vc.ar->type, cdd->draw_handle_view);
+ WM_cursor_modal_restore(cdd->vc.win);
+ }
+
+ if (cdd->stroke_elem_pool) {
+ BLI_mempool_destroy(cdd->stroke_elem_pool);
+ }
+
+ MEM_freeN(cdd);
+ op->customdata = NULL;
+ }
+}
+
+/**
+ * Initialize values before calling 'exec' (when running interactively).
+ */
+static void curve_draw_exec_precalc(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "corner_angle");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : (float)M_PI;
+ RNA_property_float_set(op->ptr, prop, corner_angle);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "error_threshold");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+
+ /* error isnt set so we'll have to calculate it from the pixel values */
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem, *selem_prev;
+
+ float len_3d = 0.0f, len_2d = 0.0f;
+ float scale_px; /* pixel to local space scale */
+
+ int i = 0;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_prev = BLI_mempool_iterstep(&iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ len_3d += len_v3v3(selem->location_local, selem_prev->location_local);
+ len_2d += len_v2v2(selem->mval, selem_prev->mval);
+ selem_prev = selem;
+ }
+ scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f;
+ float error_threshold = (cps->error_threshold * U.pixelsize) * scale_px;
+ RNA_property_float_set(op->ptr, prop, error_threshold);
+ }
+
+ if ((cps->radius_taper_start != 0.0f) ||
+ (cps->radius_taper_end != 0.0f))
+ {
+ /* note, we could try to de-duplicate the length calculations above */
+ const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ BLI_mempool_iter iter;
+ struct StrokeElem *selem, *selem_prev;
+
+ float *lengths = MEM_mallocN(sizeof(float) * stroke_len, __func__);
+ struct StrokeElem **selem_array = MEM_mallocN(sizeof(*selem_array) * stroke_len, __func__);
+ lengths[0] = 0.0f;
+
+ float len_3d = 0.0f;
+
+ int i = 1;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_prev = BLI_mempool_iterstep(&iter);
+ selem_array[0] = selem_prev;
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ const float len_3d_segment = len_v3v3(selem->location_local, selem_prev->location_local);
+ len_3d += len_3d_segment;
+ lengths[i] = len_3d;
+ selem_array[i] = selem;
+ selem_prev = selem;
+ }
+
+ if (cps->radius_taper_start != 0.0f) {
+ const float len_taper_max = cps->radius_taper_start * len_3d;
+ for (i = 0; i < stroke_len && lengths[i] < len_taper_max; i++) {
+ const float pressure_new = selem_array[i]->pressure * (lengths[i] / len_taper_max);
+ stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
+ }
+ }
+
+ if (cps->radius_taper_end != 0.0f) {
+ const float len_taper_max = cps->radius_taper_end * len_3d;
+ const float len_taper_min = len_3d - len_taper_max;
+ for (i = stroke_len - 1; i > 0 && lengths[i] > len_taper_min; i--) {
+ const float pressure_new = selem_array[i]->pressure * ((len_3d - lengths[i]) / len_taper_max);
+ stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
+ }
+ }
+
+ MEM_freeN(lengths);
+ MEM_freeN(selem_array);
+ }
+}
+
+static int curve_draw_exec(bContext *C, wmOperator *op)
+{
+ if (op->customdata == NULL) {
+ if (!curve_draw_init(C, op, false)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ struct CurveDrawData *cdd = op->customdata;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+ Object *obedit = cdd->vc.scene->obedit;
+ Curve *cu = obedit->data;
+ ListBase *nurblist = object_editcurve_get(obedit);
+
+ int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ const bool is_3d = (cu->flag & CU_3D) != 0;
+ invert_m4_m4(obedit->imat, obedit->obmat);
+
+ if (BLI_mempool_count(cdd->stroke_elem_pool) == 0) {
+ curve_draw_stroke_from_operator(op);
+ stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+ }
+
+ ED_curve_deselect_all(cu->editnurb);
+
+ const float radius_min = cps->radius_min;
+ const float radius_max = cps->radius_max;
+ const float radius_range = cps->radius_max - cps->radius_min;
+
+ Nurb *nu = MEM_callocN(sizeof(Nurb), __func__);
+ nu->pntsv = 1;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->flag |= CU_SMOOTH;
+
+ const bool use_pressure_radius =
+ (cps->flag & CURVE_PAINT_FLAG_PRESSURE_RADIUS) ||
+ ((cps->radius_taper_start != 0.0f) ||
+ (cps->radius_taper_end != 0.0f));
+
+ if (cdd->curve_type == CU_BEZIER) {
+ nu->type = CU_BEZIER;
+
+#ifdef USE_SPLINE_FIT
+
+ /* Allow to interpolate multiple channels */
+ int dims = 3;
+ struct {
+ int radius;
+ } coords_indices;
+ coords_indices.radius = use_pressure_radius ? dims++ : -1;
+
+ float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
+
+ float *cubic_spline = NULL;
+ unsigned int cubic_spline_len = 0;
+
+ /* error in object local space */
+ const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
+ const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+ float *co = coords;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), co += dims) {
+ copy_v3_v3(co, selem->location_local);
+ if (coords_indices.radius != -1) {
+ co[coords_indices.radius] = selem->pressure;
+ }
+
+ /* remove doubles */
+ if ((co != coords) && UNLIKELY(memcmp(co, co - dims, sizeof(float) * dims) == 0)) {
+ co -= dims;
+ stroke_len--;
+ }
+ }
+ }
+
+ unsigned int *corners = NULL;
+ unsigned int corners_len = 0;
+
+ if (corner_angle < (float)M_PI) {
+ /* this could be configurable... */
+ const float corner_radius_min = error_threshold / 8;
+ const float corner_radius_max = error_threshold * 2;
+ const unsigned int samples_max = 16;
+
+ curve_fit_corners_detect_fl(
+ (const float *)coords, stroke_len, dims,
+ corner_radius_min, corner_radius_max,
+ samples_max, corner_angle,
+ &corners, &corners_len);
+ }
+
+ unsigned int *corners_index = NULL;
+ unsigned int corners_index_len = 0;
+
+ const int result = curve_fit_cubic_to_points_fl(
+ coords, stroke_len, dims, error_threshold,
+ corners, corners_len,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+
+ MEM_freeN(coords);
+ if (corners) {
+ free(corners);
+ }
+
+ if (result == 0) {
+ nu->pntsu = cubic_spline_len;
+ nu->bezt = MEM_callocN(sizeof(BezTriple) * nu->pntsu, __func__);
+
+ float *co = cubic_spline;
+ BezTriple *bezt = nu->bezt;
+ for (int j = 0; j < cubic_spline_len; j++, bezt++, co += (dims * 3)) {
+ const float *handle_l = co + (dims * 0);
+ const float *pt = co + (dims * 1);
+ const float *handle_r = co + (dims * 2);
+
+ copy_v3_v3(bezt->vec[0], handle_l);
+ copy_v3_v3(bezt->vec[1], pt);
+ copy_v3_v3(bezt->vec[2], handle_r);
+
+ if (coords_indices.radius != -1) {
+ bezt->radius = (pt[coords_indices.radius] * cdd->radius.range) + cdd->radius.min;
+ }
+ else {
+ bezt->radius = radius_max;
+ }
+
+ bezt->h1 = bezt->h2 = HD_ALIGN; /* will set to free in second pass */
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ }
+
+ if (corners_index) {
+ /* ignore the first and last */
+ for (unsigned int i = 1; i < corners_index_len - 1; i++) {
+ bezt = &nu->bezt[corners_index[i]];
+ bezt->h1 = bezt->h2 = HD_FREE;
+ }
+ }
+ }
+
+ if (corners_index) {
+ free(corners_index);
+ }
+
+ if (cubic_spline) {
+ free(cubic_spline);
+ }
+
+#else
+ nu->pntsu = stroke_len;
+ nu->bezt = MEM_callocN(nu->pntsu * sizeof(BezTriple), __func__);
+
+ BezTriple *bezt = nu->bezt;
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ copy_v3_v3(bezt->vec[1], selem->location_local);
+ if (!is_3d) {
+ bezt->vec[1][2] = 0.0f;
+ }
+
+ if (use_pressure_radius) {
+ bezt->radius = selem->pressure;
+ }
+ else {
+ bezt->radius = radius_max;
+ }
+
+ bezt->h1 = bezt->h2 = HD_AUTO;
+
+ bezt->f1 |= SELECT;
+ bezt->f2 |= SELECT;
+ bezt->f3 |= SELECT;
+
+ bezt++;
+ }
+ }
+#endif
+
+ BKE_nurb_handles_calc(nu);
+ }
+ else { /* CU_POLY */
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ nu->pntsu = stroke_len;
+ nu->type = CU_POLY;
+ nu->bp = MEM_callocN(nu->pntsu * sizeof(BPoint), __func__);
+
+ BPoint *bp = nu->bp;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ copy_v3_v3(bp->vec, selem->location_local);
+ if (!is_3d) {
+ bp->vec[2] = 0.0f;
+ }
+
+ if (use_pressure_radius) {
+ bp->radius = (selem->pressure * radius_range) + radius_min;
+ }
+ else {
+ bp->radius = cps->radius_max;
+ }
+ bp->f1 = SELECT;
+ bp->vec[3] = 1.0f;
+
+ bp++;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(nurblist, nu);
+
+ BKE_curve_nurb_active_set(cu, nu);
+ cu->actvert = nu->pntsu - 1;
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
+
+ curve_draw_exit(op);
+
+ return OPERATOR_FINISHED;
+}
+
+static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (RNA_struct_property_is_set(op->ptr, "stroke")) {
+ return curve_draw_exec(C, op);
+ }
+
+ if (!curve_draw_init(C, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ struct CurveDrawData *cdd = op->customdata;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+
+ /* fallback (incase we can't find the depth on first test) */
+ {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ float center[3];
+ negate_v3_v3(center, cdd->vc.rv3d->ofs);
+ ED_view3d_win_to_3d(cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
+ copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world);
+ }
+
+ cdd->draw_handle_view = ED_region_draw_cb_activate(
+ cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
+ WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+
+ {
+ View3D *v3d = cdd->vc.v3d;
+ RegionView3D *rv3d = cdd->vc.rv3d;
+ Object *obedit = cdd->vc.obedit;
+ Curve *cu = obedit->data;
+
+ const float *plane_no = NULL;
+ const float *plane_co = NULL;
+
+ if ((cu->flag & CU_3D) == 0) {
+ /* 2D overrides other options */
+ plane_co = obedit->obmat[3];
+ plane_no = obedit->obmat[2];
+ cdd->project.use_plane = true;
+ }
+ else {
+ if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
+ (v3d->drawtype > OB_WIRE))
+ {
+ view3d_get_transformation(cdd->vc.ar, cdd->vc.rv3d, NULL, &cdd->mats);
+
+ /* needed or else the draw matrix can be incorrect */
+ view3d_operator_needs_opengl(C);
+
+ ED_view3d_autodist_init(cdd->vc.scene, cdd->vc.ar, cdd->vc.v3d, 0);
+
+ if (cdd->vc.rv3d->depths) {
+ cdd->vc.rv3d->depths->damaged = true;
+ }
+
+ ED_view3d_depth_update(cdd->vc.ar);
+
+ if (cdd->vc.rv3d->depths != NULL) {
+ cdd->project.use_depth = true;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
+ cdd->project.use_depth = false;
+ }
+ }
+
+ /* use view plane (when set or as fallback when surface can't be found) */
+ if (cdd->project.use_depth == false) {
+ plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);
+ plane_no = rv3d->viewinv[2];
+ cdd->project.use_plane = true;
+ }
+
+ if (cdd->project.use_depth && (cdd->curve_type != CU_POLY)) {
+ cdd->sample.use_substeps = true;
+ }
+ }
+
+ if (cdd->project.use_plane) {
+ normalize_v3_v3(cdd->project.plane, plane_no);
+ cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, plane_co);
+ }
+ }
+
+ if (is_modal == false) {
+ curve_draw_event_add_first(op, event);
+ }
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void curve_draw_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ curve_draw_exit(op);
+}
+
+
+/* Modal event handling of frame changing */
+static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int ret = OPERATOR_RUNNING_MODAL;
+ struct CurveDrawData *cdd = op->customdata;
+
+ UNUSED_VARS(C, op);
+
+ if (event->type == cdd->init_event_type) {
+ if (event->val == KM_RELEASE) {
+ ED_region_tag_redraw(cdd->vc.ar);
+
+ curve_draw_exec_precalc(op);
+
+ curve_draw_stroke_to_operator(op);
+
+ curve_draw_exec(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
+ ED_region_tag_redraw(cdd->vc.ar);
+ curve_draw_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ else if (ELEM(event->type, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ curve_draw_event_add_first(op, event);
+ }
+ }
+ else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (cdd->state == CURVE_DRAW_PAINTING) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > SQUARE(STROKE_SAMPLE_DIST_MIN_PX)) {
+ curve_draw_event_add(op, event);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void CURVE_OT_draw(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Draw Curve";
+ ot->idname = "CURVE_OT_draw";
+ ot->description = "Draw a freehand spline";
+
+ /* api callbacks */
+ ot->exec = curve_draw_exec;
+ ot->invoke = curve_draw_invoke;
+ ot->cancel = curve_draw_cancel;
+ ot->modal = curve_draw_modal;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_distance(
+ ot->srna, "error_threshold", 0.0f, 0.0f, 10.0f, "Error",
+ "Error distance threshold (in object units)",
+ 0.0001f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
+
+ prop = RNA_def_float_distance(
+ ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index b5d9283f6c6..0329598d711 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -35,10 +35,13 @@
#include <math.h>
#include <float.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_sys_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_polyfill2d.h"
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -82,6 +85,7 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */
GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */
+ GP_DRAWDATA_HQ_FILL = (1 << 9) /* Use high quality fill */
} eDrawStrokeFlags;
@@ -325,36 +329,186 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
/* --------------- Stroke Fills ----------------- */
-/* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short UNUSED(thickness),
- short UNUSED(dflag), short sflag,
- int offsx, int offsy, int winx, int winy)
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
{
- bGPDspoint *pt;
- int i;
+ bGPDspoint *pt0 = &points[0];
+ bGPDspoint *pt1 = &points[1];
+ bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
- BLI_assert(totpoints >= 3);
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
- /* As an initial implementation, we use the OpenGL filled polygon drawing
- * here since it's the easiest option to implement for this case. It does
- * come with limitations (notably for concave shapes), though it shouldn't
- * be much of an issue in most cases.
- */
- glBegin(GL_POLYGON);
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
- for (i = 0, pt = points; i < totpoints; i++, pt++) {
- if (sflag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ points2d[i][0] = dot_v3v3(loc, locx);
+ points2d[i][1] = dot_v3v3(loc, locy);
+ }
+
+ /* Concave (-1), Convex (1), or Autodetect (0)? */
+ *r_direction = (int)locy[2];
+}
+
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
+static void gp_triangulate_stroke_fill(bGPDstroke *gps)
+{
+ BLI_assert(gps->totpoints >= 3);
+ gps->tot_triangles = gps->totpoints - 2;
+
+ /* allocate memory for temporary areas */
+ unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+ float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
+
+ int direction = 0;
+
+ /* convert to 2d and triangulate */
+ gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+ BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
+
+ /* save triangulation data in stroke cache */
+ if (gps->tot_triangles > 0) {
+ if (gps->triangles == NULL) {
+ gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
}
else {
- float co[2];
-
- gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
+ gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+ }
+
+ int i;
+
+ for (i = 0; i < gps->tot_triangles; i++) {
+ bGPDtriangle *stroke_triangle = &gps->triangles[i];
+ stroke_triangle->v1 = tmp_triangles[i][0];
+ stroke_triangle->v2 = tmp_triangles[i][1];
+ stroke_triangle->v3 = tmp_triangles[i][2];
}
}
+ else {
+ /* No triangles needed - Free anything allocated previously */
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+
+ gps->triangles = NULL;
+ }
- glEnd();
+ /* disable recalculation flag */
+ if (gps->flag & GP_STROKE_RECALC_CACHES) {
+ gps->flag &= ~GP_STROKE_RECALC_CACHES;
+ }
+
+ /* clear memory */
+ if (tmp_triangles) MEM_freeN(tmp_triangles);
+ if (points2d) MEM_freeN(points2d);
+}
+
+
+/* draw fills for shapes */
+static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short dflag, int offsx, int offsy, int winx, int winy)
+{
+ BLI_assert(gps->totpoints >= 3);
+
+ /* Triangulation fill if high quality flag is enabled */
+ if (dflag & GP_DRAWDATA_HQ_FILL) {
+ bGPDtriangle *stroke_triangle;
+ bGPDspoint *pt;
+ int i;
+
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+ gp_triangulate_stroke_fill(gps);
+ }
+
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ BLI_assert(gps->tot_triangles >= 1);
+ glBegin(GL_TRIANGLES);
+ for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* vertex 1 */
+ pt = &gps->points[stroke_triangle->v1];
+ glVertex3fv(&pt->x);
+
+ /* vertex 2 */
+ pt = &gps->points[stroke_triangle->v2];
+ glVertex3fv(&pt->x);
+
+ /* vertex 3 */
+ pt = &gps->points[stroke_triangle->v3];
+ glVertex3fv(&pt->x);
+ }
+ else {
+ float co[2];
+
+ /* vertex 1 */
+ pt = &gps->points[stroke_triangle->v1];
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+
+ /* vertex 2 */
+ pt = &gps->points[stroke_triangle->v2];
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+
+ /* vertex 3 */
+ pt = &gps->points[stroke_triangle->v3];
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+ }
+ }
+ glEnd();
+ }
+ else {
+ /* As an initial implementation, we use the OpenGL filled polygon drawing
+ * here since it's the easiest option to implement for this case. It does
+ * come with limitations (notably for concave shapes), though it works well
+ * enough for many simple situations.
+ *
+ * We keep this legacy implementation around despite now having the high quality
+ * fills, as this is necessary for keeping everything working nicely for files
+ * created using old versions of Blender which may have depended on the artifacts
+ * the old fills created.
+ */
+ bGPDspoint *pt;
+ int i;
+
+ glBegin(GL_POLYGON);
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ glVertex3fv(&pt->x);
+ }
+ else {
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+ }
+ }
+ glEnd();
+ }
}
/* ----- Existing Strokes Drawing (3D and Point) ------ */
@@ -695,7 +849,7 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
/* 3D Fill */
if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
glColor4fv(fill_color);
- gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
}
/* 3D Stroke */
@@ -730,7 +884,7 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
/* 2D - Fill */
if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
glColor4fv(fill_color);
- gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
}
/* 2D Strokes... */
@@ -890,7 +1044,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
copy_v3_v3(color, gpl->color);
}
- if (gpl->gstep) {
+ if (gpl->gstep > 0) {
bGPDframe *gf;
float fac;
@@ -907,13 +1061,16 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
break;
}
}
- else {
+ else if (gpl->gstep == 0) {
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->prev) {
color[3] = (alpha / 7);
gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
}
}
+ else {
+ /* don't draw - disabled */
+ }
/* 2) Now draw next frames */
@@ -924,7 +1081,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
copy_v3_v3(color, gpl->color);
}
- if (gpl->gstep_next) {
+ if (gpl->gstep_next > 0) {
bGPDframe *gf;
float fac;
@@ -941,13 +1098,16 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
break;
}
}
- else {
+ else if (gpl->gstep_next == 0) {
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->next) {
color[3] = (alpha / 4);
gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
}
}
+ else {
+ /* don't draw - disabled */
+ }
/* 3) restore alpha */
glColor4fv(gpl->color);
@@ -990,7 +1150,10 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* volumetric strokes... */
GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
-
+
+ /* HQ fills... */
+ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
+
/* fill strokes... */
// XXX: this is not a very good limit
GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 09a72c10457..a49b3362155 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -460,7 +460,8 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* make a copy of stroke, then of its points array */
gpsn = MEM_dupallocN(gps);
gpsn->points = MEM_dupallocN(gps->points);
-
+ /* duplicate triangle information */
+ gpsn->triangles = MEM_dupallocN(gps->triangles);
/* append stroke to frame */
BLI_addtail(&gpf->strokes, gpsn);
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 43751dbadb9..df05397258c 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -766,8 +766,9 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
new_stroke = MEM_dupallocN(gps);
new_stroke->points = MEM_dupallocN(gps->points);
- new_stroke->next = new_stroke->prev = NULL;
+ new_stroke->triangles = MEM_dupallocN(gps->triangles);
+ new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
/* Adjust all the stroke's points, so that the strokes
@@ -905,7 +906,7 @@ static void gpencil_toggle_brush_cursor(bContext *C, bool enable)
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
{
const char *brush_name = NULL;
- char str[256] = "";
+ char str[UI_MAX_DRAW_STR] = "";
RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
@@ -1284,6 +1285,12 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
break;
}
+
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
}
CTX_DATA_END;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 03d5ed3e24f..bd1697b9a54 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -170,6 +170,11 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
+ /* initialize triangle memory - will be calculated on next redraw */
+ gpsd->triangles = NULL;
+ gpsd->flag |= GP_STROKE_RECALC_CACHES;
+ gpsd->tot_triangles = 0;
+
/* now, make a new points array, and copy of the relevant parts */
gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
@@ -223,6 +228,10 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
gpsd = MEM_dupallocN(gps);
gpsd->points = MEM_dupallocN(gps->points);
+ /* triangle information - will be calculated on next redraw */
+ gpsd->flag |= GP_STROKE_RECALC_CACHES;
+ gpsd->triangles = NULL;
+
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
BLI_addtail(&new_strokes, gpsd);
@@ -287,11 +296,13 @@ void ED_gpencil_strokes_copybuf_free(void)
for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
gpsn = gps->next;
- MEM_freeN(gps->points);
+ if (gps->points) MEM_freeN(gps->points);
+ if (gps->triangles) MEM_freeN(gps->triangles);
+
BLI_freelinkN(&gp_strokes_copypastebuf, gps);
}
- BLI_listbase_clear(&gp_strokes_copypastebuf);
+ gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
}
/* --------------------- */
@@ -336,6 +347,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
gpsd = MEM_dupallocN(gps);
gpsd->points = MEM_dupallocN(gps->points);
+ /* triangles cache - will be recalculated on next redraw */
+ gpsd->flag |= GP_STROKE_RECALC_CACHES;
+ gpsd->tot_triangles = 0;
+ gpsd->triangles = NULL;
+
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
BLI_addtail(&gp_strokes_copypastebuf, gpsd);
@@ -371,6 +387,14 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
/* --------------------- */
/* Paste selected strokes */
+static int gp_strokes_paste_poll(bContext *C)
+{
+ /* 1) Must have GP layer to paste to...
+ * 2) Copy buffer must at least have something (though it may be the wrong sort...)
+ */
+ return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
+}
+
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -450,8 +474,11 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
bGPDstroke *new_stroke = MEM_dupallocN(gps);
new_stroke->points = MEM_dupallocN(gps->points);
- new_stroke->next = new_stroke->prev = NULL;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke->triangles = NULL;
+
+ new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
}
}
@@ -472,7 +499,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* callbacks */
ot->exec = gp_strokes_paste_exec;
- ot->poll = gp_stroke_edit_poll;
+ ot->poll = gp_strokes_paste_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -672,6 +699,7 @@ static int gp_delete_selected_strokes(bContext *C)
if (gps->flag & GP_STROKE_SELECT) {
/* free stroke memory arrays, then stroke itself */
if (gps->points) MEM_freeN(gps->points);
+ if (gps->triangles) MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
changed = true;
@@ -732,6 +760,9 @@ static int gp_dissolve_selected_points(bContext *C)
if (tot <= 0) {
/* remove the entire stroke */
MEM_freeN(gps->points);
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
BLI_freelinkN(&gpf->strokes, gps);
}
else {
@@ -753,6 +784,10 @@ static int gp_dissolve_selected_points(bContext *C)
gps->points = new_points;
gps->totpoints = tot;
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
/* deselect the stroke, since none of its selected points will still be selected */
gps->flag &= ~GP_STROKE_SELECT;
}
@@ -842,6 +877,11 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
tGPDeleteIsland *island = &islands[idx];
bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ /* initialize triangle memory - to be calculated on next redraw */
+ new_stroke->triangles = NULL;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke->tot_triangles = 0;
+
/* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
new_stroke->totpoints = island->end_idx - island->start_idx + 1;
new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
@@ -886,6 +926,9 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
/* Delete the old stroke */
MEM_freeN(gps->points);
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
BLI_freelinkN(&gpf->strokes, gps);
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 368da618a1d..dd28f6ac531 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -177,6 +177,8 @@ void GPENCIL_OT_select_linked(struct wmOperatorType *ot);
void GPENCIL_OT_select_grouped(struct wmOperatorType *ot);
void GPENCIL_OT_select_more(struct wmOperatorType *ot);
void GPENCIL_OT_select_less(struct wmOperatorType *ot);
+void GPENCIL_OT_select_first(struct wmOperatorType *ot);
+void GPENCIL_OT_select_last(struct wmOperatorType *ot);
void GPENCIL_OT_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_delete(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 9f5633ae668..cf9828f8105 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -140,6 +140,36 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
+
+ /* Sculpting ------------------------------------- */
+
+ /* Brush-Based Editing:
+ * EKEY + LMB = Single stroke, draw immediately
+ * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
+ *
+ * For the modal version, use D+E -> Sculpt
+ */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+
+
+ /* Shift-FKEY = Sculpt Strength */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
+
+ /* Ctrl-FKEY = Sculpt Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
+
+
/* Selection ------------------------------------- */
/* select all */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
@@ -160,6 +190,15 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
+ /* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early)
+ * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey
+ * combo doesn't seem to see much use under standard scenarios?
+ */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
/* normal select */
WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
@@ -229,36 +268,6 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
-
- /* Brush-Based Editing:
- * EKEY + LMB = Single stroke, draw immediately
- * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
- *
- * For the modal version, use D+E -> Sculpt
- */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
-
-
- /* Shift-FKEY = Sculpt Strength */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
-
- /* Ctrl-FKEY = Sculpt Brush Size */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
-
-
-
-
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -314,6 +323,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_select_grouped);
WM_operatortype_append(GPENCIL_OT_select_more);
WM_operatortype_append(GPENCIL_OT_select_less);
+ WM_operatortype_append(GPENCIL_OT_select_first);
+ WM_operatortype_append(GPENCIL_OT_select_last);
WM_operatortype_append(GPENCIL_OT_duplicate);
WM_operatortype_append(GPENCIL_OT_delete);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 2a81b481ed1..fba2f30e715 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -572,6 +572,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->flag = gpd->sbuffer_sflag;
gps->inittime = p->inittime;
+ /* enable recalculation flag by default (only used if hq fill) */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
/* allocate enough memory for a continuous array for storage points */
int sublevel = gpl->sublevel;
int new_totpoints = gps->totpoints;
@@ -580,7 +583,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
new_totpoints += new_totpoints - 1;
}
gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points");
-
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
@@ -710,11 +716,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
- /* smooth stroke - only if there's something to do */
- /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
+ /* smooth stroke after subdiv - only if there's something to do
+ * for each iteration, the factor is reduced to get a better smoothing without changing too much
+ * the original stroke
+ */
if (gpl->draw_smoothfac > 0.0f) {
- for (i = 0; i < gps->totpoints; i++) {
- gp_smooth_stroke(gps, i, gpl->draw_smoothfac, false);
+ float reduce = 0.0f;
+ for (int r = 0; r < gpl->draw_smoothlvl; ++r) {
+ for (i = 0; i < gps->totpoints; i++) {
+ /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
+ gp_smooth_stroke(gps, i, gpl->draw_smoothfac - reduce, false);
+ }
+ reduce += 0.25f; // reduce the factor
}
}
@@ -795,6 +808,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* just free stroke */
if (gps->points)
MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
@@ -807,6 +822,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* 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);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 0a36df471f1..b6482786b4f 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -349,6 +349,126 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
}
/* ********************************************** */
+/* Select First */
+
+static int gpencil_select_first_exec(bContext *C, wmOperator *op)
+{
+ const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* skip stroke if we're only manipulating selected strokes */
+ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
+ continue;
+ }
+
+ /* select first point */
+ BLI_assert(gps->totpoints >= 1);
+
+ gps->points->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+
+ /* deselect rest? */
+ if ((extend == false) && (gps->totpoints > 1)) {
+ /* start from index 1, to skip the first point that we'd just selected... */
+ bGPDspoint *pt = &gps->points[1];
+ int i = 1;
+
+ for (; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_first(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select First";
+ ot->idname = "GPENCIL_OT_select_first";
+ ot->description = "Select first point in Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_select_first_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only",
+ "Only select the first point of strokes that already have points selected");
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
+}
+
+/* ********************************************** */
+/* Select First */
+
+static int gpencil_select_last_exec(bContext *C, wmOperator *op)
+{
+ const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* skip stroke if we're only manipulating selected strokes */
+ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
+ continue;
+ }
+
+ /* select last point */
+ BLI_assert(gps->totpoints >= 1);
+
+ gps->points[gps->totpoints - 1].flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+
+ /* deselect rest? */
+ if ((extend == false) && (gps->totpoints > 1)) {
+ /* don't include the last point... */
+ bGPDspoint *pt = gps->points;
+ int i = 1;
+
+ for (; i < gps->totpoints - 1; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_last(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Last";
+ ot->idname = "GPENCIL_OT_select_last";
+ ot->description = "Select last point in Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_select_last_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only",
+ "Only select the last point of strokes that already have points selected");
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
+}
+
+/* ********************************************** */
/* Select More */
static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 34e640a4b7b..c39a3aa5cfc 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -41,7 +41,7 @@
#include "BLI_listbase.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 64cb0b5bb6a..b2c6107ab61 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -569,6 +569,10 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
/* add the point itself */
madd_v3_v3fl(sco, &pt->x, average_fac);
+ if (affect_pressure) {
+ pressure += pt->pressure * average_fac;
+ }
+
/* n-steps before/after current point */
// XXX: review how the endpoints are treated by this algorithm
// XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
@@ -637,3 +641,21 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
}
/* ******************************************************** */
+
+
+bool ED_gpencil_stroke_minmax(
+ const bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3])
+{
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {;
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
+ }
+ return changed;
+}
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index e45e5f5e7ab..0ac5c17a552 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -143,6 +143,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
*/
void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect);
+void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
/**
* glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef.
@@ -150,9 +152,13 @@ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int ty
* needs glaDefine2DArea to be set.
*/
void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect);
+void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY);
+void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
/* 2D Drawing Assistance */
@@ -205,9 +211,21 @@ void bgl_get_mats(bglMats *mats);
void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter,
struct ColorManagedViewSettings *view_settings,
struct ColorManagedDisplaySettings *display_settings);
+void glaDrawImBuf_glsl_clipping(struct ImBuf *ibuf, float x, float y, int zoomfilter,
+ struct ColorManagedViewSettings *view_settings,
+ struct ColorManagedDisplaySettings *display_settings,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y);
+
/* Draw imbuf on a screen, preferably using GLSL display transform */
void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter);
+void glaDrawImBuf_glsl_ctx_clipping(const struct bContext *C,
+ struct ImBuf *ibuf,
+ float x, float y,
+ int zoomfilter,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y);
void glaDrawBorderCorners(const struct rcti *border, float zoomx, float zoomy);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 3c8442218be..fb4897c6532 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -544,10 +544,10 @@ void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, List
/* free the copy/paste buffer */
-void free_fmodifiers_copybuf(void);
+void ANIM_fmodifiers_copybuf_free(void);
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
+ * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
* - active: only copy the active modifier
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 15c68378b9a..904132b8876 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -74,7 +74,10 @@ typedef struct EditBone {
float xwidth, length, zwidth; /* put them in order! transform uses this as scale */
float ease1, ease2;
float rad_head, rad_tail;
-
+ float roll1, roll2;
+ float curveOutX, curveOutY;
+ float curveInX, curveInY;
+ float scaleIn, scaleOut;
float oldlength; /* for envelope scaling */
short segments;
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 0f638c449ad..255827db373 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -86,6 +86,10 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_minmax(
+ const struct bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3]);
+
/* ----------- Grease Pencil Operators ----------------- */
void ED_keymap_gpencil(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index bbfa8ec7b1d..fae3e3677a0 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -272,7 +272,7 @@ void sample_fcurve(struct FCurve *fcu);
/* ----------- */
-void free_anim_copybuf(void);
+void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data,
const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 0ad1dc4d8c1..81e2558e765 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -288,6 +288,14 @@ bool ANIM_remove_driver(struct ReportList *reports, struct ID *id, const char rn
/* -------- */
+/* Clear copy-paste buffer for drivers */
+void ANIM_drivers_copybuf_free(void);
+
+/* Clear copy-paste buffer for driver variable sets */
+void ANIM_driver_vars_copybuf_free(void);
+
+/* -------- */
+
/* Returns whether there is a driver in the copy/paste buffer to paste */
bool ANIM_driver_can_paste(void);
@@ -302,6 +310,17 @@ bool ANIM_copy_driver(struct ReportList *reports, struct ID *id, const char rna_
*/
bool ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
+/* -------- */
+
+/* Checks if there are driver variables in the copy/paste buffer */
+bool ANIM_driver_vars_can_paste(void);
+
+/* Copy the given driver's variables to the buffer */
+bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu);
+
+/* Paste the variables in the buffer to the given FCurve */
+bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace);
+
/* ************ Auto-Keyframing ********************** */
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 5436ef4b06b..de798b1fce2 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -80,7 +80,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
-void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob);
+void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
void EDBM_mesh_load(struct Object *ob);
struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 85370de0013..6a558d1c185 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -67,6 +67,7 @@ void ED_region_panels(
const bool vertical);
void ED_region_header_init(struct ARegion *ar);
void ED_region_header(const struct bContext *C, struct ARegion *ar);
+void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw);
void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index db8085a6696..933f480a554 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -43,6 +43,8 @@ struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperatorType;
+struct Main;
+struct SnapObjectContext;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
@@ -156,19 +158,6 @@ void BIF_draw_manipulator(const struct bContext *C);
/* Snapping */
-
-typedef struct DepthPeel {
- struct DepthPeel *next, *prev;
-
- float depth;
- float p[3];
- float no[3];
- struct Object *ob;
- int flag;
-} DepthPeel;
-
-struct ListBase;
-
typedef enum SnapSelect {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
@@ -177,37 +166,23 @@ typedef enum SnapSelect {
#define SNAP_MIN_DISTANCE 30
-bool peelObjectsTransForm(
- struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+bool peelObjectsTransform(
+ struct TransInfo *t, const float mval[2],
+ SnapSelect snap_select, bool use_peel_object,
/* return args */
- struct ListBase *r_depth_peels);
-bool peelObjectsContext(
- struct bContext *C, const float mval[2], SnapSelect snap_select,
+ float r_loc[3], float r_no[3], float *r_thickness);
+bool peelObjectsSnapContext(
+ struct SnapObjectContext *sctx,
+ const float mval[2],
+ SnapSelect snap_select, bool use_peel_object,
/* return args */
- struct ListBase *r_depth_peels);
+ float r_loc[3], float r_no[3], float *r_thickness);
+
bool snapObjectsTransform(
struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], float *r_dist_px);
-bool snapObjectsContext(
- struct bContext *C, const float mval[2], SnapSelect snap_select,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px);
-/* taks args for all settings */
-bool snapObjectsEx(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_mode,
- float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px);
-bool snapObjectsRayEx(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_mode,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- struct Object **r_ob, float r_obmat[4][4]);
-
+ float r_loc[3], float r_no[3]);
bool snapNodesTransform(
struct TransInfo *t, const int mval[2], SnapSelect snap_select,
/* return args */
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
new file mode 100644
index 00000000000..900b7593f2e
--- /dev/null
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_transform_snap_object_context.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__
+#define __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__
+
+struct BMVert;
+struct BMEdge;
+struct BMFace;
+
+struct ListBase;
+struct Scene;
+struct Main;
+struct Object;
+struct ARegion;
+struct View3D;
+
+/* transform_snap_object.c */
+
+/* ED_transform_snap_object_*** API */
+
+/** used for storing multiple hits */
+struct SnapObjectHitDepth {
+ struct SnapObjectHitDepth *next, *prev;
+
+ float depth;
+ float co[3];
+ float no[3];
+ int index;
+
+ struct Object *ob;
+ float obmat[4][4];
+
+ /* needed to tell which ray-cast this was part of,
+ * the same object may be part of many ray-casts when dupli's are used. */
+ unsigned int ob_uuid;
+};
+
+struct SnapObjectParams {
+ int snap_select; /* SnapSelect */
+ union {
+ unsigned int snap_to : 4;
+ /* snap_target_flag: Snap to vert/edge/face. */
+ unsigned int snap_to_flag : 4;
+ };
+ /* use editmode cage */
+ unsigned int use_object_edit : 1;
+ /* special context sensitive handling for the active object */
+ unsigned int use_object_active : 1;
+};
+
+enum {
+ SNAP_OBJECT_USE_CACHE = (1 << 0),
+};
+
+typedef struct SnapObjectContext SnapObjectContext;
+SnapObjectContext *ED_transform_snap_object_context_create(
+ struct Main *bmain, struct Scene *scene, int flag);
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(
+ struct Main *bmain, struct Scene *scene, int flag,
+ /* extra args for view3d */
+ struct ARegion *ar, struct View3D *v3d);
+void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
+
+/* callbacks to filter how snap works */
+void ED_transform_snap_object_context_set_editmesh_callbacks(
+ SnapObjectContext *sctx,
+ bool (*test_vert_fn)(struct BMVert *, void *user_data),
+ bool (*test_edge_fn)(struct BMEdge *, void *user_data),
+ bool (*test_face_fn)(struct BMFace *, void *user_data),
+ void *user_data);
+
+bool ED_transform_snap_object_project_ray_ex(
+ struct SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ struct Object **r_ob, float r_obmat[4][4]);
+bool ED_transform_snap_object_project_ray(
+ SnapObjectContext *sctx,
+ const float ray_origin[3], const float ray_direction[3], float *ray_depth,
+ float r_co[3], float r_no[3]);
+
+bool ED_transform_snap_object_project_ray_all(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_start[3], const float ray_normal[3],
+ float ray_depth, bool sort,
+ struct ListBase *r_hit_list);
+
+bool ED_transform_snap_object_project_view3d_ex(
+ struct SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ float r_loc[3], float r_no[3], int *r_index);
+bool ED_transform_snap_object_project_view3d(
+ struct SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3]);
+bool ED_transform_snap_object_project_view3d_mixed(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval_fl[2], float *dist_px,
+ bool use_depth,
+ float r_co[3], float r_no[3]);
+
+bool ED_transform_snap_object_project_all_view3d_ex(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ float ray_depth, bool sort,
+ ListBase *r_hit_list);
+
+#endif /* __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ */
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index d8a3f5e75f5..c23c2eed890 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -396,18 +396,6 @@ void ED_view3d_operator_properties_viewmat_set(struct bContext *C, struct wmOper
void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, int *winy, float persmat[4][4]);
#endif
-bool ED_view3d_snap_from_region(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
- const float mval[2], float dist_px,
- bool use_depth, bool use_obedit,
- bool use_vert, bool use_edge, bool use_face,
- float r_co[3], float r_no[3]);
-
-bool ED_view3d_snap_from_ray(
- struct Scene *scene,
- const float ray_start[3], const float ray_normal[3],
- float r_co[3]);
-
/* render */
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 76ff9e0fbd8..2c80701bf69 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -1020,3 +1020,25 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC)
DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
DEF_VICO(KEYTYPE_EXTREME_VEC)
DEF_VICO(KEYTYPE_JITTER_VEC)
+
+DEF_VICO(COLORSET_01_VEC)
+DEF_VICO(COLORSET_02_VEC)
+DEF_VICO(COLORSET_03_VEC)
+DEF_VICO(COLORSET_04_VEC)
+DEF_VICO(COLORSET_05_VEC)
+DEF_VICO(COLORSET_06_VEC)
+DEF_VICO(COLORSET_07_VEC)
+DEF_VICO(COLORSET_08_VEC)
+DEF_VICO(COLORSET_09_VEC)
+DEF_VICO(COLORSET_10_VEC)
+DEF_VICO(COLORSET_11_VEC)
+DEF_VICO(COLORSET_12_VEC)
+DEF_VICO(COLORSET_13_VEC)
+DEF_VICO(COLORSET_14_VEC)
+DEF_VICO(COLORSET_15_VEC)
+DEF_VICO(COLORSET_16_VEC)
+DEF_VICO(COLORSET_17_VEC)
+DEF_VICO(COLORSET_18_VEC)
+DEF_VICO(COLORSET_19_VEC)
+DEF_VICO(COLORSET_20_VEC)
+
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 06831576507..88924495ae5 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -232,13 +232,8 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
if (IS_AUTOKEY_ON(scene)) {
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
- int index;
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
@@ -249,13 +244,8 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
if (IS_AUTOKEY_ON(scene)) {
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
- int index;
-
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 023439fddee..10ab85a6142 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -60,7 +60,7 @@
#include "PIL_time.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -2945,18 +2945,6 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
}
#ifdef WITH_INPUT_IME
-/* test if the translation context allows IME input - used to
- * avoid weird character drawing if IME inputs non-ascii chars */
-static bool ui_ime_is_lang_supported(void)
-{
- const char *uilng = BLT_lang_get();
- const bool is_lang_supported = STREQ(uilng, "zh_CN") ||
- STREQ(uilng, "zh_TW") ||
- STREQ(uilng, "ja_JP");
-
- return ((U.transopts & USER_DOTRANSLATE) && is_lang_supported);
-}
-
/* enable ime, and set up uibut ime data */
static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
{
@@ -3078,7 +3066,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
#ifdef WITH_INPUT_IME
- if (is_num_but == false && ui_ime_is_lang_supported()) {
+ if (is_num_but == false && BLT_lang_is_ime_supported()) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -3405,7 +3393,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
#ifdef WITH_INPUT_IME
&&
!is_ime_composing &&
- !WM_event_is_ime_switch(event)
+ (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported())
#endif
)
{
@@ -6537,7 +6525,6 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_but_tooltip_timer_remove(C, but);
UI_popup_block_invoke(C, menu_change_shortcut, but);
}
@@ -6559,7 +6546,6 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_but_tooltip_timer_remove(C, but);
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
@@ -6608,8 +6594,6 @@ static bool ui_but_menu(bContext *C, uiBut *but)
return false;
}
- UI_but_tooltip_timer_remove(C, but);
-
/* highly unlikely getting the label ever fails */
UI_but_string_info_get(C, but, &label, NULL);
@@ -6778,10 +6762,19 @@ static bool ui_but_menu(bContext *C, uiBut *but)
ICON_NONE, "UI_OT_unset_property_button");
}
+ if (is_array_component) {
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", true);
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", false);
+ }
+ else {
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", true);
+ }
+
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
ICON_NONE, "UI_OT_copy_data_path_button");
- uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
- ICON_NONE, "UI_OT_copy_to_selected_button");
uiItemS(layout);
}
@@ -7378,7 +7371,6 @@ static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
static bool ui_region_contains_point_px(ARegion *ar, int x, int y)
{
- uiBlock *block = ar->uiblocks.first;
rcti winrct;
/* scale down area rect to exclude shadow */
@@ -7386,7 +7378,7 @@ static bool ui_region_contains_point_px(ARegion *ar, int x, int y)
/* check if the mouse is in the region */
if (!BLI_rcti_isect_pt(&winrct, x, y)) {
- for (block = ar->uiblocks.first; block; block = block->next)
+ for (uiBlock *block = ar->uiblocks.first; block; block = block->next)
block->auto_open = false;
return false;
@@ -7880,6 +7872,19 @@ static void button_activate_exit(
ui_apply_but_undo(but);
ui_apply_but_autokey(C, but);
+#ifdef USE_ALLSELECT
+ {
+ /* only RNA from this button is used */
+ uiBut but_temp = *but;
+ uiSelectContextStore *selctx_data = &data->select_others;
+ for (int i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ but_temp.rnapoin = other->ptr;
+ ui_apply_but_autokey(C, &but_temp);
+ }
+ }
+#endif
+
/* popup menu memory */
if (block->flag & UI_BLOCK_POPUP_MEMORY)
ui_popup_menu_memory_set(block, but);
@@ -8446,8 +8451,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
}
if (val == KM_PRESS) {
- if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
- ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl)))
+ if ((ELEM(type, UPARROWKEY, DOWNARROWKEY) && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) ||
+ ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))))
{
const int value_orig = RNA_property_int_get(&listbox->rnapoin, listbox->rnaprop);
int value, min, max, inc;
@@ -9818,9 +9823,17 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
retval = ui_handler_panel_region(C, event, ar, listbox ? listbox : but);
- if (retval == WM_UI_HANDLER_CONTINUE && listbox)
+ if (retval == WM_UI_HANDLER_CONTINUE && listbox) {
retval = ui_handle_list_event(C, event, ar, listbox);
+ /* interactions with the listbox should disable tips */
+ if (retval == WM_UI_HANDLER_BREAK) {
+ if (but) {
+ UI_but_tooltip_timer_remove(C, but);
+ }
+ }
+ }
+
if (retval == WM_UI_HANDLER_CONTINUE) {
if (but)
retval = ui_handle_button_event(C, event, but);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 7be153e942e..0da21fd442f 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -511,6 +511,63 @@ static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER);
}
+static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
+{
+ bTheme *btheme = UI_GetTheme();
+ ThemeWireColor *cs = &btheme->tarm[index];
+
+ /* Draw three bands of color: One per color
+ * x-----a-----b-----c
+ * | N | S | A |
+ * x-----a-----b-----c
+ */
+ const int a = x + w / 3;
+ const int b = x + w / 3 * 2;
+ const int c = x + w;
+
+ /* XXX: Include alpha into this... */
+ /* normal */
+ glColor3ubv(cs->solid);
+ glRecti(x, y, a, y + h);
+
+ /* selected */
+ glColor3ubv(cs->select);
+ glRecti(a, y, b, y + h);
+
+ /* active */
+ glColor3ubv(cs->active);
+ glRecti(b, y, c, y + h);
+}
+
+#define DEF_VICON_COLORSET_DRAW_NTH(prefix, index) \
+ static void vicon_colorset_draw_##prefix(int x, int y, int w, int h, float alpha) \
+ { \
+ vicon_colorset_draw(index, x, y, w, h, alpha); \
+ }
+
+DEF_VICON_COLORSET_DRAW_NTH(01, 0)
+DEF_VICON_COLORSET_DRAW_NTH(02, 1)
+DEF_VICON_COLORSET_DRAW_NTH(03, 2)
+DEF_VICON_COLORSET_DRAW_NTH(04, 3)
+DEF_VICON_COLORSET_DRAW_NTH(05, 4)
+DEF_VICON_COLORSET_DRAW_NTH(06, 5)
+DEF_VICON_COLORSET_DRAW_NTH(07, 6)
+DEF_VICON_COLORSET_DRAW_NTH(08, 7)
+DEF_VICON_COLORSET_DRAW_NTH(09, 8)
+DEF_VICON_COLORSET_DRAW_NTH(10, 9)
+DEF_VICON_COLORSET_DRAW_NTH(11, 10)
+DEF_VICON_COLORSET_DRAW_NTH(12, 11)
+DEF_VICON_COLORSET_DRAW_NTH(13, 12)
+DEF_VICON_COLORSET_DRAW_NTH(14, 13)
+DEF_VICON_COLORSET_DRAW_NTH(15, 14)
+DEF_VICON_COLORSET_DRAW_NTH(16, 15)
+DEF_VICON_COLORSET_DRAW_NTH(17, 16)
+DEF_VICON_COLORSET_DRAW_NTH(18, 17)
+DEF_VICON_COLORSET_DRAW_NTH(19, 18)
+DEF_VICON_COLORSET_DRAW_NTH(20, 19)
+
+#undef DEF_VICON_COLORSET_DRAW_NTH
+
#ifndef WITH_HEADLESS
static void init_brush_icons(void)
@@ -741,6 +798,27 @@ static void init_internal_icons(void)
def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
+
+ def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01);
+ def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02);
+ def_internal_vicon(VICO_COLORSET_03_VEC, vicon_colorset_draw_03);
+ def_internal_vicon(VICO_COLORSET_04_VEC, vicon_colorset_draw_04);
+ def_internal_vicon(VICO_COLORSET_05_VEC, vicon_colorset_draw_05);
+ def_internal_vicon(VICO_COLORSET_06_VEC, vicon_colorset_draw_06);
+ def_internal_vicon(VICO_COLORSET_07_VEC, vicon_colorset_draw_07);
+ def_internal_vicon(VICO_COLORSET_08_VEC, vicon_colorset_draw_08);
+ def_internal_vicon(VICO_COLORSET_09_VEC, vicon_colorset_draw_09);
+ def_internal_vicon(VICO_COLORSET_10_VEC, vicon_colorset_draw_10);
+ def_internal_vicon(VICO_COLORSET_11_VEC, vicon_colorset_draw_11);
+ def_internal_vicon(VICO_COLORSET_12_VEC, vicon_colorset_draw_12);
+ def_internal_vicon(VICO_COLORSET_13_VEC, vicon_colorset_draw_13);
+ def_internal_vicon(VICO_COLORSET_14_VEC, vicon_colorset_draw_14);
+ def_internal_vicon(VICO_COLORSET_15_VEC, vicon_colorset_draw_15);
+ def_internal_vicon(VICO_COLORSET_16_VEC, vicon_colorset_draw_16);
+ def_internal_vicon(VICO_COLORSET_17_VEC, vicon_colorset_draw_17);
+ def_internal_vicon(VICO_COLORSET_18_VEC, vicon_colorset_draw_18);
+ def_internal_vicon(VICO_COLORSET_19_VEC, vicon_colorset_draw_19);
+ def_internal_vicon(VICO_COLORSET_20_VEC, vicon_colorset_draw_20);
IMB_freeImBuf(b16buf);
IMB_freeImBuf(b32buf);
@@ -1342,7 +1420,7 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
Object *ob = CTX_data_active_object(C);
SpaceImage *sima;
EnumPropertyItem *items = NULL;
- int tool, mode = 0;
+ int tool = PAINT_TOOL_DRAW, mode = 0;
/* XXX: this is not nice, should probably make brushes
* be strictly in one paint mode only to avoid
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index bacae0a28c6..7a9c3e827cf 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -557,7 +557,7 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
}
/* Reports to Textblock Operator ------------------------ */
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 2fdd84b626b..62b373c58c8 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1679,7 +1679,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
BLF_size(fontid, fstyle_points, U.dpi);
BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, 1.0f, 1.0f, 1.0f, 0.25f);
+ BLF_shadow(fontid, 3, (const float[4]){1.0f, 1.0f, 1.0f, 0.25f});
BLF_shadow_offset(fontid, -1, -1);
BLI_assert(UI_panel_category_is_visible(ar));
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index abd395afbe0..9e49d7e7e90 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -1788,10 +1788,20 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
- ui_region_temp_remove(C, CTX_wm_screen(C), handle->region);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *sc = CTX_wm_screen(C);
+
+ ui_region_temp_remove(C, sc, handle->region);
+
+ /* reset to region cursor (only if there's not another menu open) */
+ if (BLI_listbase_is_empty(&sc->regionbase)) {
+ ED_region_cursor_set(win, CTX_wm_area(C), CTX_wm_region(C));
+ /* in case cursor needs to be changed again */
+ WM_event_add_mousemove(C);
+ }
if (handle->scrolltimer)
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer);
+ WM_event_remove_timer(CTX_wm_manager(C), win, handle->scrolltimer);
}
/**
@@ -1965,11 +1975,19 @@ uiPopupBlockHandle *ui_popup_block_create(
void *arg)
{
wmWindow *window = CTX_wm_window(C);
+ uiBut *activebut = UI_context_active_but_get(C);
static ARegionType type;
ARegion *ar;
uiBlock *block;
uiPopupBlockHandle *handle;
+ /* disable tooltips from buttons below */
+ if (activebut) {
+ UI_but_tooltip_timer_remove(C, activebut);
+ }
+ /* standard cursor by default */
+ WM_cursor_set(window, CURSOR_STD);
+
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
@@ -2988,7 +3006,8 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
}
if (mt->poll && mt->poll(C, mt) == 0)
- return OPERATOR_CANCELLED;
+ /* cancel but allow event to pass through, just like operators do */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
layout = UI_pie_menu_layout(pie);
@@ -3219,7 +3238,8 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
}
if (mt->poll && mt->poll(C, mt) == 0)
- return OPERATOR_CANCELLED;
+ /* cancel but allow event to pass through, just like operators do */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE);
layout = UI_popup_menu_layout(pup);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index bfde02dbefd..423c48e5f55 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -160,7 +160,8 @@ void UI_fontstyle_draw_ex(
/* set the flag */
if (fs->shadow) {
font_flag |= BLF_SHADOW;
- BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
+ const float shadow_color[4] = {fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha};
+ BLF_shadow(fs->uifont_id, fs->shadow, shadow_color);
BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
}
if (fs->kerning == 1) {
@@ -251,7 +252,8 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch
if (fs->shadow) {
BLF_enable(fs->uifont_id, BLF_SHADOW);
- BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
+ const float shadow_color[4] = {fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha};
+ BLF_shadow(fs->uifont_id, fs->shadow, shadow_color);
BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a47d60812b4..a3b04e1c9bc 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2947,7 +2947,11 @@ void uiTemplateList(
/* We tag the list id with the list type... */
BLI_snprintf(ui_list_id, sizeof(ui_list_id), "%s_%s", ui_list_type->idname, list_id ? list_id : "");
- ar = CTX_wm_region(C);
+ /* Allows to work in popups. */
+ ar = CTX_wm_menu(C);
+ if (ar == NULL) {
+ ar = CTX_wm_region(C);
+ }
ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id));
if (!ui_list) {
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 841b76c676b..19e0b55374e 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -859,10 +859,17 @@ static void widget_draw_icon(
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
}
-
- /* extra feature allows more alpha blending */
- if ((but->type == UI_BTYPE_LABEL) && but->a1 == 1.0f)
- alpha *= but->a2;
+ else if ((but->type == UI_BTYPE_LABEL)) {
+ /* extra feature allows more alpha blending */
+ if (but->a1 == 1.0f) {
+ alpha *= but->a2;
+ }
+ }
+ else if (ELEM(but->type, UI_BTYPE_BUT)) {
+ if (but->flag & UI_BUT_DISABLED) {
+ alpha *= 0.5f;
+ }
+ }
glEnable(GL_BLEND);
@@ -3042,6 +3049,15 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
wcol->shaded = 0;
wcol->alpha_check = (wcol->inner[3] < 255);
+
+ if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ /* Now we reduce alpha of the inner color (i.e. the color shown)
+ * so that this setting can look greyed out, while retaining
+ * the checkboard (for transparent values). This is needed
+ * here as the effects of ui_widget_color_disabled() are overwritten.
+ */
+ wcol->inner[3] /= 2;
+ }
widgetbase_draw(&wtb, wcol);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index b1d2e329da1..e2e2413c717 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -96,7 +96,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
static char setting = 0;
const char *cp = error;
- /* ensure we're not getting a color after running BKE_userdef_free */
+ /* ensure we're not getting a color after running BKE_blender_userdef_free */
BLI_assert(BLI_findindex(&U.themes, theme_active) != -1);
BLI_assert(colorid != TH_UNDEFINED);
@@ -786,9 +786,14 @@ static void ui_theme_init_new_do(ThemeSpace *ts)
rgba_char_args_set(ts->panel_text_hi, 255, 255, 255, 255);
#endif
+ ts->panelcolors.show_back = false;
+ ts->panelcolors.show_header = false;
+ rgba_char_args_set(ts->panelcolors.back, 114, 114, 114, 128);
+ rgba_char_args_set(ts->panelcolors.header, 0, 0, 0, 25);
+
rgba_char_args_set(ts->button, 145, 145, 145, 245);
rgba_char_args_set(ts->button_title, 0, 0, 0, 255);
- rgba_char_args_set(ts->button_text, 0, 0, 0, 255);
+ rgba_char_args_set(ts->button_text, 0, 0, 0, 255);
rgba_char_args_set(ts->button_text_hi, 255, 255, 255, 255);
rgba_char_args_set(ts->list, 165, 165, 165, 255);
@@ -848,14 +853,9 @@ void ui_theme_init_default(void)
/* UI buttons */
ui_widget_color_init(&btheme->tui);
-
+
btheme->tui.iconfile[0] = 0;
- btheme->tui.panel.show_back = false;
- btheme->tui.panel.show_header = false;
- rgba_char_args_set(btheme->tui.panel.header, 0, 0, 0, 25);
-
rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
-
rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255);
@@ -872,10 +872,6 @@ void ui_theme_init_default(void)
ui_theme_init_new(btheme);
/* space view3d */
- btheme->tv3d.panelcolors.show_back = false;
- btheme->tv3d.panelcolors.show_header = false;
- rgba_char_args_set_fl(btheme->tv3d.panelcolors.back, 0.45, 0.45, 0.45, 0.5);
- rgba_char_args_set_fl(btheme->tv3d.panelcolors.header, 0, 0, 0, 0.01);
rgba_char_args_set_fl(btheme->tv3d.back, 0.225, 0.225, 0.225, 1.0);
rgba_char_args_set(btheme->tv3d.text, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.text_hi, 255, 255, 255, 255);
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 822bb429f9e..e3e8f35e7d8 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -194,12 +194,12 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
/******************** add vertex *********************/
-static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
- const float point_co[2], const float u,
- MaskSplinePoint *reference_point, const bool reference_adjacent)
+static void setup_vertex_point(
+ Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
+ const float point_co[2], const float u, const float ctime,
+ const MaskSplinePoint *reference_point, const bool reference_adjacent)
{
- MaskSplinePoint *prev_point = NULL;
- MaskSplinePoint *next_point = NULL;
+ const MaskSplinePoint *reference_parent_point = NULL;
BezTriple *bezt;
float co[3];
@@ -247,14 +247,44 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
else {
bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
}
+
+ reference_parent_point = reference_point;
}
else if (reference_adjacent) {
if (spline->tot_point != 1) {
- int index = (int)(new_point - spline->points);
- prev_point = &spline->points[(index - 1) % spline->tot_point];
- next_point = &spline->points[(index + 1) % spline->tot_point];
+ MaskSplinePoint *prev_point, *next_point, *close_point;
- bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1);
+ const int index = (int)(new_point - spline->points);
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ prev_point = &spline->points[mod_i(index - 1, spline->tot_point)];
+ next_point = &spline->points[mod_i(index + 1, spline->tot_point)];
+ }
+ else {
+ prev_point = (index != 0) ? &spline->points[index - 1] : NULL;
+ next_point = (index != spline->tot_point - 1) ? &spline->points[index + 1] : NULL;
+ }
+
+ if (prev_point && next_point) {
+ close_point = (len_squared_v2v2(new_point->bezt.vec[1], prev_point->bezt.vec[1]) <
+ len_squared_v2v2(new_point->bezt.vec[1], next_point->bezt.vec[1])) ?
+ prev_point : next_point;
+ }
+ else {
+ close_point = prev_point ? prev_point : next_point;
+ }
+
+ /* handle type */
+ char handle_type = 0;
+ if (prev_point) {
+ handle_type = prev_point->bezt.h2;
+ }
+ if (next_point) {
+ handle_type = MAX2(next_point->bezt.h2, handle_type);
+ }
+ bezt->h1 = bezt->h2 = handle_type;
+
+ /* parent */
+ reference_parent_point = close_point;
/* note, we may want to copy other attributes later, radius? pressure? color? */
}
@@ -264,7 +294,20 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
copy_v3_v3(bezt->vec[1], co);
copy_v3_v3(bezt->vec[2], co);
- BKE_mask_parent_init(&new_point->parent);
+ if (reference_parent_point) {
+ new_point->parent = reference_parent_point->parent;
+
+ if (new_point->parent.id) {
+ float parent_matrix[3][3];
+ BKE_mask_point_parent_matrix_get(new_point, ctime, parent_matrix);
+ invert_m3(parent_matrix);
+ mul_m3_v2(parent_matrix, new_point->bezt.vec[1]);
+ }
+ }
+ else {
+ BKE_mask_parent_init(&new_point->parent);
+ }
+
if (spline->tot_point != 1) {
BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
}
@@ -348,6 +391,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, tangent, true, true,
&masklay, &spline, &point, &u, NULL))
{
+ Scene *scene = CTX_data_scene(C);
+ const float ctime = CFRA;
+
MaskSplinePoint *new_point;
int point_index = point - spline->points;
@@ -357,7 +403,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
new_point = &spline->points[point_index + 1];
- setup_vertex_point(mask, spline, new_point, co, u, NULL, true);
+ setup_vertex_point(mask, spline, new_point, co, u, ctime, NULL, true);
/* TODO - we could pass the spline! */
BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true);
@@ -375,6 +421,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
{
+ Scene *scene = CTX_data_scene(C);
+ const float ctime = CFRA;
+
MaskSpline *spline;
MaskSplinePoint *point;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
@@ -454,7 +503,7 @@ static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay
masklay->act_point = new_point;
- setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, false);
+ setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false);
if (masklay->splines_shapes.first) {
point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
@@ -468,34 +517,28 @@ static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay
static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
{
+ Scene *scene = CTX_data_scene(C);
+ const float ctime = CFRA;
+
MaskSpline *spline;
- MaskSplinePoint *point;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
if (!masklay) {
/* if there's no masklay currently operationg on, create new one */
masklay = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
- spline = NULL;
- point = NULL;
- }
- else {
- finSelectedSplinePoint(masklay, &spline, &point, true);
}
ED_mask_select_toggle_all(mask, SEL_DESELECT);
- if (!spline) {
- /* no selected splines in active masklay, create new spline */
- spline = BKE_mask_spline_add(masklay);
- }
+ spline = BKE_mask_spline_add(masklay);
masklay->act_spline = spline;
new_point = spline->points;
masklay->act_point = new_point;
- setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, false);
+ setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false);
{
int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 847a7b5336e..242cbf79a83 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -44,6 +44,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -69,16 +71,15 @@ typedef struct {
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
-#define HEADER_LENGTH 180
-
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
"Vertex Only: %s (V), Offset: %s, Segments: %d");
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
@@ -97,7 +98,7 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
- BLI_snprintf(msg, HEADER_LENGTH, str, type_str,
+ BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
offset_str, RNA_int_get(op->ptr, "segments"));
@@ -137,8 +138,11 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->mesh_backup = EDBM_redo_state_store(em);
opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
- opdata->twtype = v3d->twtype;
- v3d->twtype = 0;
+
+ if (v3d) {
+ opdata->twtype = v3d->twtype;
+ v3d->twtype = 0;
+ }
}
return true;
@@ -206,7 +210,9 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel);
- v3d->twtype = opdata->twtype;
+ if (v3d) {
+ v3d->twtype = opdata->twtype;
+ }
G.moving = 0;
}
MEM_freeN(opdata);
@@ -327,7 +333,6 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- int segments = RNA_int_get(op->ptr, "segments");
const bool has_numinput = hasNumInput(&opdata->num_input);
/* Modal numinput active, try to handle numeric inputs first... */
@@ -368,6 +373,19 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
+ case MOUSEPAN: {
+ float delta = 0.02f * (event->y - event->prevy);
+ if (opdata->segments >= 1 && opdata->segments + delta < 1)
+ opdata->segments = 1;
+ else
+ opdata->segments += delta;
+ RNA_int_set(op->ptr, "segments", (int)opdata->segments);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ handled = true;
+ break;
+ }
+
/* Note this will prevent padplus and padminus to ever activate modal numinput.
* This is not really an issue though, as we only expect positive values here...
* Else we could force them to only modify segments number when shift is pressed, or so.
@@ -378,8 +396,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE)
break;
- segments++;
- RNA_int_set(op->ptr, "segments", segments);
+ opdata->segments = opdata->segments + 1;
+ RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -390,8 +408,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE)
break;
- segments = max_ii(segments - 1, 1);
- RNA_int_set(op->ptr, "segments", segments);
+ opdata->segments = max_ff(opdata->segments - 1, 1);
+ RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 161159d0be0..1dfb1cddd2c 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -673,7 +673,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_dupli_extrude_cursor_invoke;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -732,8 +732,17 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
- RNA_float_set_array(op->ptr, "center", ED_view3d_cursor3d_get(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
+ PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "center");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d));
+ }
+ if (rv3d) {
+ prop = RNA_struct_find_property(op->ptr, "axis");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]);
+ }
+ }
return edbm_spin_exec(C, op);
}
@@ -859,8 +868,17 @@ static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
- RNA_float_set_array(op->ptr, "center", ED_view3d_cursor3d_get(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
+ PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "center");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d));
+ }
+ if (rv3d) {
+ prop = RNA_struct_find_property(op->ptr, "axis");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]);
+ }
+ }
return edbm_screw_exec(C, op);
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 937547c99ef..3e0747f055f 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -44,6 +44,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -54,8 +56,6 @@
#include "mesh_intern.h" /* own include */
-#define HEADER_LENGTH 180
-
typedef struct {
float old_thickness;
float old_depth;
@@ -83,7 +83,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, "
"Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)");
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
@@ -95,7 +95,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness"));
BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth"));
}
- BLI_snprintf(msg, HEADER_LENGTH, str,
+ BLI_snprintf(msg, sizeof(msg), str,
flts_str,
flts_str + NUM_STR_REP_LEN,
WM_bool_as_string(opdata->modify_depth),
@@ -143,8 +143,10 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->mesh_backup = EDBM_redo_state_store(em);
opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
- opdata->twtype = v3d->twtype;
- v3d->twtype = 0;
+ if (v3d) {
+ opdata->twtype = v3d->twtype;
+ v3d->twtype = 0;
+ }
}
return true;
@@ -162,7 +164,9 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel);
- v3d->twtype = opdata->twtype;
+ if (v3d) {
+ v3d->twtype = opdata->twtype;
+ }
G.moving = 0;
}
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index c35a36069a7..f1c1e4105d0 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -47,6 +47,8 @@
#include "BIF_gl.h"
+#include "UI_interface.h"
+
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
@@ -87,6 +89,9 @@ typedef struct RingSelOpData {
bool extend;
bool do_cut;
+
+ float cuts; /* cuts as float so smooth mouse pan works in small increments */
+ float smoothness;
} RingSelOpData;
/* modal loop selection drawing callback */
@@ -501,6 +506,8 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
lcd->em = BKE_editmesh_from_object(lcd->ob);
lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
lcd->do_cut = do_cut;
+ lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
+ lcd->smoothness = RNA_float_get(op->ptr, "smoothness");
initNumInput(&lcd->num);
lcd->num.idx_max = 1;
@@ -648,9 +655,9 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- float smoothness = RNA_float_get(op->ptr, "smoothness");
- int cuts = RNA_int_get(op->ptr, "number_cuts");
RingSelOpData *lcd = op->customdata;
+ float cuts = lcd->cuts;
+ float smoothness = lcd->smoothness;
bool show_cuts = false;
const bool has_numinput = hasNumInput(&lcd->num);
@@ -662,20 +669,10 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* using the keyboard to input the number of cuts */
/* Modal numinput active, try to handle numeric inputs first... */
if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
- float values[2] = {(float)cuts, smoothness};
+ float values[2] = {cuts, smoothness};
applyNumInput(&lcd->num, values);
-
- /* allow zero so you can backspace and type in a value
- * otherwise 1 as minimum would make more sense */
- cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
- smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
-
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
- RNA_float_set(op->ptr, "smoothness", smoothness);
-
- ED_region_tag_redraw(lcd->ar);
+ cuts = values[0];
+ smoothness = values[1];
}
else {
bool handled = false;
@@ -708,25 +705,28 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(lcd->ar);
handled = true;
break;
+ case MOUSEPAN:
+ if (event->alt == 0) {
+ cuts += 0.02f * (event->y - event->prevy);
+ if (cuts < 1 && lcd->cuts >= 1)
+ cuts = 1;
+ }
+ else {
+ smoothness += 0.002f * (event->y - event->prevy);
+ }
+ handled = true;
+ break;
case PADPLUSKEY:
case PAGEUPKEY:
case WHEELUPMOUSE: /* change number of cuts */
if (event->val == KM_RELEASE)
break;
if (event->alt == 0) {
- cuts++;
- cuts = CLAMPIS(cuts, 0, SUBD_CUTS_MAX);
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
+ cuts += 1;
}
else {
- smoothness = min_ff(smoothness + 0.05f, SUBD_SMOOTH_MAX);
- RNA_float_set(op->ptr, "smoothness", smoothness);
- show_cuts = true;
+ smoothness += 0.05f;
}
-
- ED_region_tag_redraw(lcd->ar);
handled = true;
break;
case PADMINUS:
@@ -734,27 +734,19 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
case WHEELDOWNMOUSE: /* change number of cuts */
if (event->val == KM_RELEASE)
break;
-
if (event->alt == 0) {
- cuts = max_ii(cuts - 1, 1);
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
+ cuts = max_ff(cuts - 1, 1);
}
else {
- smoothness = max_ff(smoothness - 0.05f, -SUBD_SMOOTH_MAX);
- RNA_float_set(op->ptr, "smoothness", smoothness);
- show_cuts = true;
+ smoothness -= 0.05f;
}
-
- ED_region_tag_redraw(lcd->ar);
handled = true;
break;
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
if (!has_numinput) {
lcd->vc.mval[0] = event->mval[0];
lcd->vc.mval[1] = event->mval[1];
- loopcut_mouse_move(lcd, cuts);
+ loopcut_mouse_move(lcd, (int)lcd->cuts);
ED_region_tag_redraw(lcd->ar);
handled = true;
@@ -764,32 +756,39 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Modal numinput inactive, try to handle numeric inputs last... */
if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
- float values[2] = {(float)cuts, smoothness};
+ float values[2] = {cuts, smoothness};
applyNumInput(&lcd->num, values);
+ cuts = values[0];
+ smoothness = values[1];
+ }
+ }
- /* allow zero so you can backspace and type in a value
- * otherwise 1 as minimum would make more sense */
- cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
- smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
-
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
- RNA_float_set(op->ptr, "smoothness", smoothness);
+ if (cuts != lcd->cuts) {
+ /* allow zero so you can backspace and type in a value
+ * otherwise 1 as minimum would make more sense */
+ lcd->cuts = CLAMPIS(cuts, 0, SUBD_CUTS_MAX);
+ RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts);
+ ringsel_find_edge(lcd, (int)lcd->cuts);
+ show_cuts = true;
+ ED_region_tag_redraw(lcd->ar);
+ }
- ED_region_tag_redraw(lcd->ar);
- }
+ if (smoothness != lcd->smoothness) {
+ lcd->smoothness = CLAMPIS(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
+ RNA_float_set(op->ptr, "smoothness", lcd->smoothness);
+ show_cuts = true;
+ ED_region_tag_redraw(lcd->ar);
}
if (show_cuts) {
Scene *sce = CTX_data_scene(C);
- char buf[64 + NUM_STR_REP_LEN * 2];
+ char buf[UI_MAX_DRAW_STR];
char str_rep[NUM_STR_REP_LEN * 2];
if (hasNumInput(&lcd->num)) {
outputNumInput(&lcd->num, str_rep, &sce->unit);
}
else {
- BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", cuts);
+ BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts);
BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness);
}
BLI_snprintf(buf, sizeof(buf), IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"),
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 55ed0e521ea..4431712e720 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -588,6 +588,17 @@ static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
return NULL;
}
+static BMElem *edbm_elem_active_elem_or_face_get(BMesh *bm)
+{
+ BMElem *ele = BM_mesh_active_elem_get(bm);
+
+ if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) {
+ ele = (BMElem *)bm->act_face;
+ }
+
+ return ele;
+}
+
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (RNA_struct_property_is_set(op->ptr, "index")) {
@@ -605,7 +616,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
view3d_operator_needs_opengl(C);
BMElem *ele_src, *ele_dst;
- if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
!(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
{
/* special case, toggle edge tags even when we don't have a path */
@@ -655,7 +666,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
}
BMElem *ele_src, *ele_dst;
- if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
!(ele_dst = EDBM_elem_from_index_any(em, index)))
{
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index c7a7828f3b2..9e71e646b1a 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -77,14 +77,14 @@ static float edbm_rip_edgedist_squared(
const float dist_2d = len_v2v2(vec1, vec2);
if (dist_2d > FLT_EPSILON) {
const float dist = inset / dist_2d;
- BLI_assert(finite(dist));
+ BLI_assert(isfinite(dist));
interp_v2_v2v2(vec1, vec1, vec2, dist);
interp_v2_v2v2(vec2, vec2, vec1, dist);
}
}
dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
- BLI_assert(finite(dist_sq));
+ BLI_assert(isfinite(dist_sq));
return dist_sq;
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 17250fbfb09..84ae35fae6e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2430,13 +2430,10 @@ static void select_linked_delimit_validate(BMesh *bm, int *delimit)
}
}
-static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit)
+static void select_linked_delimit_begin(BMesh *bm, int delimit)
{
struct DelimitData delimit_data = {0};
- BMIter iter;
- BMEdge *e;
-
if (delimit & BMO_DELIM_UV) {
delimit_data.cd_loop_type = CD_MLOOPUV;
delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
@@ -2447,19 +2444,13 @@ static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit
/* grr, shouldn't need to alloc BMO flags here */
BM_mesh_elem_toolflags_ensure(bm);
- if (selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- const bool is_walk_ok = (
- (select_linked_delimit_test(e, delimit, &delimit_data) == false));
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
- }
- }
- else {
- /* don't delimit selected edges in vert/edge mode */
+ {
+ BMIter iter;
+ BMEdge *e;
+
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
const bool is_walk_ok = (
- BM_elem_flag_test(e, BM_ELEM_SELECT) ||
(select_linked_delimit_test(e, delimit, &delimit_data) == false));
BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
@@ -2491,7 +2482,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
select_linked_delimit_validate(bm, &delimit);
if (delimit) {
- select_linked_delimit_begin(em->bm, em->selectmode, delimit);
+ select_linked_delimit_begin(em->bm, delimit);
}
if (em->selectmode & SCE_SELECT_VERTEX) {
@@ -2501,6 +2492,17 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
}
+ /* exclude all delimited verts */
+ if (delimit) {
+ BMEdge *e;
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) {
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+
BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
@@ -2546,8 +2548,17 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
else if (em->selectmode & SCE_SELECT_EDGE) {
BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(
+ e, BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG)));
+ }
+ }
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
}
BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
@@ -2661,7 +2672,7 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in
select_linked_delimit_validate(bm, &delimit);
if (delimit) {
- select_linked_delimit_begin(bm, em->selectmode, delimit);
+ select_linked_delimit_begin(bm, delimit);
}
/* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index ee33f5f1655..ba17684dd39 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -68,6 +68,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -301,20 +302,30 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ ar, CTX_wm_view3d(C));
+
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float mval[2], co_proj[3], no_dummy[3];
- float dist_px_dummy;
+ float mval[2], co_proj[3];
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- if (snapObjectsContext(
- C, mval, SNAP_NOT_OBEDIT,
- co_proj, no_dummy, &dist_px_dummy))
+ if (ED_transform_snap_object_project_view3d_mixed(
+ snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_OBEDIT,
+ .snap_to_flag = SCE_SELECT_FACE,
+ },
+ mval, NULL, true,
+ co_proj, NULL))
{
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
}
}
}
}
+
+ ED_transform_snap_object_context_destroy(snap_context);
}
@@ -532,7 +543,7 @@ void MESH_OT_edge_collapse(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int edbm_add_edge_face__smooth_get(BMesh *bm)
+static bool edbm_add_edge_face__smooth_get(BMesh *bm)
{
BMEdge *e;
BMIter iter;
@@ -700,7 +711,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
BMOperator bmop;
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
+ const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
const int totedge_orig = em->bm->totedge;
const int totface_orig = em->bm->totface;
/* when this is used to dissolve we could avoid this, but checking isnt too slow */
@@ -3001,7 +3012,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
BM_mesh_normals_update(bm_new);
- BM_mesh_bm_to_me(bm_new, base_new->object->data, false);
+ BM_mesh_bm_to_me(bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm_new);
((Mesh *)base_new->object->data)->edit_btmesh = NULL;
@@ -3284,7 +3295,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
- BM_mesh_bm_from_me(bm_old, me, false, false, 0);
+ BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
switch (type) {
case MESH_SEPARATE_MATERIAL:
@@ -3299,7 +3310,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
if (retval_iter) {
- BM_mesh_bm_to_me(bm_old, me, false);
+ BM_mesh_bm_to_me(bm_old, me, (&(struct BMeshToMeshParams){0}));
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
@@ -3566,7 +3577,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
BMOperator bmop;
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
+ const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
const int totedge_orig = em->bm->totedge;
const int totface_orig = em->bm->totface;
const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
@@ -5114,6 +5125,17 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
"bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
+ if (use_faces && totface_del) {
+ int i;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ for (i = 0; i < totface_del; i++) {
+ BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
+ }
+ BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
+ "delete geom=%hf context=%i",
+ BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
+ }
+
BMO_op_exec(em->bm, &bmop);
if (!BMO_error_occurred(em->bm)) {
@@ -5123,17 +5145,6 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
}
- if (use_faces && totface_del) {
- int i;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- for (i = 0; i < totface_del; i++) {
- BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
- }
- BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
- "delete geom=%hf context=%i",
- BM_ELEM_TAG, DEL_FACES);
- }
-
if (use_merge == false) {
struct EdgeRingOpSubdProps op_props;
mesh_operator_edgering_props_get(op, &op_props);
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 33f8455e614..82ec93c162f 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -347,7 +347,7 @@ void EDBM_selectmode_to_scene(bContext *C)
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
}
-void EDBM_mesh_make(ToolSettings *ts, Object *ob)
+void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
{
Mesh *me = ob->data;
BMesh *bm;
@@ -356,7 +356,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob)
BKE_mesh_convert_mfaces_to_mpolys(me);
}
- bm = BKE_mesh_to_bmesh(me, ob);
+ bm = BKE_mesh_to_bmesh(me, ob, add_key_index);
if (me->edit_btmesh) {
/* this happens when switching shape keys */
@@ -395,7 +395,7 @@ void EDBM_mesh_load(Object *ob)
bm->shapenr = 1;
}
- BM_mesh_bm_to_me(bm, me, false);
+ BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
#ifdef USE_TESSFACE_DEFAULT
BKE_mesh_tessface_calc(me);
@@ -533,7 +533,10 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
/* BM_mesh_validate(em->bm); */ /* for troubleshooting */
- BM_mesh_bm_to_me(em->bm, &um->me, false);
+ BM_mesh_bm_to_me(
+ em->bm, &um->me, (&(struct BMeshToMeshParams){
+ .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
+ }));
um->selectmode = em->selectmode;
um->shapenr = em->bm->shapenr;
@@ -557,7 +560,10 @@ static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
bm = BM_mesh_create(&allocsize);
- BM_mesh_bm_from_me(bm, &um->me, true, false, um->shapenr);
+ BM_mesh_bm_from_me(
+ bm, &um->me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true, .active_shapekey = um->shapenr,
+ }));
em_tmp = BKE_editmesh_create(bm, true);
*em = *em_tmp;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index a2054a5f43c..e0ddc017e93 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -582,7 +582,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
obedit = base->object;
me = obedit->data;
if (me->edit_btmesh == NULL) {
- EDBM_mesh_make(scene->toolsettings, obedit);
+ EDBM_mesh_make(scene->toolsettings, obedit, false);
exitmode = 1;
}
if (me->edit_btmesh == NULL)
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index bad835b13e7..1b2d4b7c130 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -572,7 +572,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
#else
/* toggle editmode using lower level functions so this can be called from python */
- EDBM_mesh_make(scene->toolsettings, ob);
+ EDBM_mesh_make(scene->toolsettings, ob, false);
EDBM_mesh_load(ob);
EDBM_mesh_free(me->edit_btmesh);
MEM_freeN(me->edit_btmesh);
@@ -811,9 +811,9 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
int i;
/* ignore nan verts */
- if ((finite(co[0]) == false) ||
- (finite(co[1]) == false) ||
- (finite(co[2]) == false))
+ if ((isfinite(co[0]) == false) ||
+ (isfinite(co[1]) == false) ||
+ (isfinite(co[2]) == false))
{
return NULL;
}
@@ -902,8 +902,8 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float
float cent[2];
/* ignore nan verts */
- if (isnan(uv[0]) || !finite(uv[0]) ||
- isnan(uv[1]) || !finite(uv[1])
+ if (isnan(uv[0]) || !isfinite(uv[0]) ||
+ isnan(uv[1]) || !isfinite(uv[1])
)
{
return NULL;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 888bf832042..11d96da5786 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -700,7 +700,7 @@ static void bake_startjob(void *bkv, short *stop, short *do_update, float *progr
bkr->progress = progress;
RE_test_break_cb(bkr->re, NULL, thread_break);
- G.is_break = false; /* blender_test_break uses this global */
+ G.is_break = false; /* BKE_blender_test_break uses this global */
RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob);
@@ -827,7 +827,7 @@ static int bake_image_exec(bContext *C, wmOperator *op)
bkr.reports = op->reports;
RE_test_break_cb(bkr.re, NULL, thread_break);
- G.is_break = false; /* blender_test_break uses this global */
+ G.is_break = false; /* BKE_blender_test_break uses this global */
RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL);
@@ -843,7 +843,7 @@ static int bake_image_exec(bContext *C, wmOperator *op)
/* used to redraw in 2.4x but this is just for exec in 2.5 */
if (!G.background)
- blender_test_break();
+ BKE_blender_test_break();
}
BLI_end_threads(&threads);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 38f22beff8d..06200778ee5 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -316,6 +316,27 @@ void OBJECT_OT_hide_render_set(wmOperatorType *ot)
/* ******************* toggle editmode operator ***************** */
+static bool mesh_needs_keyindex(const Mesh *me)
+{
+ if (me->key) {
+ return false; /* will be added */
+ }
+
+ for (const Object *ob = G.main->object.first; ob; ob = ob->id.next) {
+ if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
+ return true;
+ }
+ if (ob->data == me) {
+ for (const ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Hook) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/**
* Load EditMode data back into the object,
* optionally freeing the editmode data.
@@ -494,15 +515,15 @@ void ED_object_editmode_enter(bContext *C, int flag)
ok = 1;
scene->obedit = ob; /* context sees this */
- EDBM_mesh_make(scene->toolsettings, ob);
+ const bool use_key_index = mesh_needs_keyindex(ob->data);
+
+ EDBM_mesh_make(scene->toolsettings, ob, use_key_index);
em = BKE_editmesh_from_object(ob);
if (LIKELY(em)) {
/* order doesn't matter */
EDBM_mesh_normals_update(em);
BKE_editmesh_tessface_calc(em);
-
- BM_mesh_select_mode_flush(em->bm);
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MESH, scene);
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 492b6724f93..438c10c51fa 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -316,7 +316,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
BMEditMesh *em;
EDBM_mesh_load(obedit);
- EDBM_mesh_make(scene->toolsettings, obedit);
+ EDBM_mesh_make(scene->toolsettings, obedit, true);
DAG_id_tag_update(obedit->data, 0);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 84cf97ecb7c..2f10f83e276 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -136,7 +136,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
BMEditMesh *em;
EDBM_mesh_load(obedit);
- EDBM_mesh_make(scene->toolsettings, obedit);
+ EDBM_mesh_make(scene->toolsettings, obedit, true);
DAG_id_tag_update(obedit->data, 0);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 4619f998a11..414cc476be5 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -2096,14 +2096,19 @@ static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
MDeformWeight *dw = defvert_find_index(dvert, act_vgroup);
MDeformWeight *dw_mirr = defvert_find_index(dvert_mirr, act_vgroup);
- if (dw || dw_mirr) {
- if (dw_mirr == NULL)
- dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup);
- if (dw == NULL)
- dw = defvert_verify_index(dvert, act_vgroup);
-
+ if (dw && dw_mirr) {
SWAP(float, dw->weight, dw_mirr->weight);
}
+ else if (dw) {
+ dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup);
+ dw_mirr->weight = dw->weight;
+ defvert_remove_group(dvert, dw);
+ }
+ else if (dw_mirr) {
+ dw = defvert_verify_index(dvert, act_vgroup);
+ dw->weight = dw_mirr->weight;
+ defvert_remove_group(dvert_mirr, dw_mirr);
+ }
}
}
@@ -2197,28 +2202,34 @@ void ED_vgroup_mirror(Object *ob,
EDBM_verts_mirror_cache_begin(em, 0, true, false, use_topology);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
/* Go through the list of editverts and assign them */
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
- if (eve_mirr != eve) {
- sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
- sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
+ if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
+ if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
+ if (eve_mirr != eve) {
+ if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
+ sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
- if ((sel || sel_mirr) && (eve != eve_mirr)) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
+ if ((sel || sel_mirr) && (eve != eve_mirr)) {
+ dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
- VGROUP_MIRR_OP;
- totmirr++;
+ VGROUP_MIRR_OP;
+ totmirr++;
+ }
+
+ /* don't use these again */
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ BM_elem_flag_enable(eve_mirr, BM_ELEM_TAG);
+ }
}
}
-
- /* don't use these again */
- EDBM_verts_mirror_cache_clear(em, eve);
- EDBM_verts_mirror_cache_clear(em, eve_mirr);
- }
- else {
- totfail++;
+ else {
+ totfail++;
+ }
}
}
EDBM_verts_mirror_cache_end(em);
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 7cc17e4bfea..a5d2d2c8be7 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -39,7 +39,6 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_object_deform.h"
@@ -426,7 +425,7 @@ static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update
job->start = PIL_check_seconds_timer();
job->success = 1;
- G.is_break = false; /* reset blender_test_break*/
+ G.is_break = false; /* reset BKE_blender_test_break*/
/* XXX annoying hack: needed to prevent data corruption when changing
* scene frame in separate threads
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 29824a348f5..3da3a451d66 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -102,7 +102,7 @@ void update_world_cos(Object *ob, PTCacheEdit *edit);
#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
-#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
+#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
/**************************** utilities *******************************/
@@ -4111,7 +4111,9 @@ static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key)
userdata.bvhdata = data->shape_bvh;
userdata.num_hits = 0;
- BLI_bvhtree_ray_cast_all(shape_bvh->tree, key->co, dir, 0.0f, point_inside_bvh_cb, &userdata);
+ BLI_bvhtree_ray_cast_all(
+ shape_bvh->tree, key->co, dir, 0.0f, BVH_RAYCAST_DIST_MAX,
+ point_inside_bvh_cb, &userdata);
/* for any point inside a watertight mesh the number of hits is uneven */
return (userdata.num_hits % 2) == 1;
@@ -4809,3 +4811,113 @@ void PARTICLE_OT_edited_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/************************ Unify length operator ************************/
+
+static float calculate_point_length(PTCacheEditPoint *point)
+{
+ float length = 0.0f;
+ KEY_K;
+ LOOP_KEYS {
+ if (k > 0) {
+ length += len_v3v3((key - 1)->co, key->co);
+ }
+ }
+ return length;
+}
+
+static float calculate_average_length(PTCacheEdit *edit)
+{
+ int num_selected = 0;
+ float total_length = 0;
+ POINT_P;
+ LOOP_SELECTED_POINTS {
+ total_length += calculate_point_length(point);
+ ++num_selected;
+ }
+ if (num_selected == 0) {
+ return 0.0f;
+ }
+ return total_length / num_selected;
+}
+
+static void scale_point_factor(PTCacheEditPoint *point, float factor)
+{
+ float orig_prev_co[3], prev_co[3];
+ KEY_K;
+ LOOP_KEYS {
+ if (k == 0) {
+ copy_v3_v3(orig_prev_co, key->co);
+ copy_v3_v3(prev_co, key->co);
+ }
+ else {
+ float new_co[3];
+ float delta[3];
+
+ sub_v3_v3v3(delta, key->co, orig_prev_co);
+ mul_v3_fl(delta, factor);
+ add_v3_v3v3(new_co, prev_co, delta);
+
+ copy_v3_v3(orig_prev_co, key->co);
+ copy_v3_v3(key->co, new_co);
+ copy_v3_v3(prev_co, key->co);
+ }
+ }
+ point->flag |= PEP_EDIT_RECALC;
+}
+
+static void scale_point_to_length(PTCacheEditPoint *point, float length)
+{
+ const float point_length = calculate_point_length(point);
+ if (point_length != 0.0f) {
+ const float factor = length / point_length;
+ scale_point_factor(point, factor);
+ }
+}
+
+static void scale_points_to_length(PTCacheEdit *edit, float length)
+{
+ POINT_P;
+ LOOP_SELECTED_POINTS {
+ scale_point_to_length(point, length);
+ }
+ recalc_lengths(edit);
+}
+
+static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ float average_length = calculate_average_length(edit);
+ if (average_length == 0.0f) {
+ return OPERATOR_CANCELLED;
+ }
+ scale_points_to_length(edit, average_length);
+
+ PE_update_object(scene, ob, 1);
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+ }
+ else {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_unify_length(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unify Length";
+ ot->idname = "PARTICLE_OT_unify_length";
+ ot->description = "Make selected hair the same length";
+
+ /* api callbacks */
+ ot->exec = unify_length_exec;
+ ot->poll = PE_poll_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 666ed2397d2..361c058647a 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -61,6 +61,8 @@ void PARTICLE_OT_shape_cut(struct wmOperatorType *ot);
void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot);
void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
+void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
+
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index c765bff796e..5074a41ad20 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -69,6 +69,8 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
WM_operatortype_append(PARTICLE_OT_edited_clear);
+ WM_operatortype_append(PARTICLE_OT_unify_length);
+
WM_operatortype_append(OBJECT_OT_particle_system_add);
WM_operatortype_append(OBJECT_OT_particle_system_remove);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index eb8ea01f750..1203889cf0e 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -49,7 +49,8 @@
#include "DNA_view3d_types.h"
#include "DNA_userdef_types.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
+#include "BKE_blender_version.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 4ede89e1620..ab8b7d4e138 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -635,8 +635,8 @@ void ED_area_headerprint(ScrArea *sa, const char *str)
if (ar->regiontype == RGN_TYPE_HEADER) {
if (str) {
if (ar->headerstr == NULL)
- ar->headerstr = MEM_mallocN(256, "headerprint");
- BLI_strncpy(ar->headerstr, str, 256);
+ ar->headerstr = MEM_mallocN(UI_MAX_DRAW_STR, "headerprint");
+ BLI_strncpy(ar->headerstr, str, UI_MAX_DRAW_STR);
}
else if (ar->headerstr) {
MEM_freeN(ar->headerstr);
@@ -1507,6 +1507,16 @@ void ED_region_init(bContext *C, ARegion *ar)
region_update_rect(ar);
}
+void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
+{
+ if (ar && sa && ar->type && ar->type->cursor) {
+ ar->type->cursor(win, sa, ar);
+ }
+ else {
+ WM_cursor_set(win, CURSOR_STD);
+ }
+}
+
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
{
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index b7ad911b6f5..cbf87062955 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -368,7 +368,11 @@ static int get_cached_work_texture(int *r_w, int *r_h)
return texid;
}
-void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY)
+void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
+ int format, int type, int zoomfilter, void *rect,
+ float scaleX, float scaleY,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y)
{
unsigned char *uc_rect = (unsigned char *) rect;
const float *f_rect = (float *)rect;
@@ -377,6 +381,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
int texid = get_cached_work_texture(&tex_w, &tex_h);
int components;
+ const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y));
/* Specify the color outside this function, and tex will modulate it.
* This is useful for changing alpha without using glPixelTransferf()
@@ -443,11 +448,23 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0;
float rast_x = x + subpart_x * offset_x * xzoom;
float rast_y = y + subpart_y * offset_y * yzoom;
-
/* check if we already got these because we always get 2 more when doing seamless */
if (subpart_w <= seamless || subpart_h <= seamless)
continue;
-
+
+ if (use_clipping) {
+ if (rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX < clip_min_x ||
+ rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY < clip_min_y)
+ {
+ continue;
+ }
+ if (rast_x + (float)offset_left * xzoom > clip_max_x ||
+ rast_y + (float)offset_bot * yzoom > clip_max_y)
+ {
+ continue;
+ }
+ }
+
if (type == GL_FLOAT) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
@@ -497,9 +514,26 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
#endif
}
+void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h,
+ int format, int type, int zoomfilter, void *rect,
+ float scaleX, float scaleY)
+{
+ glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
+ scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f);
+}
+
void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
{
- glaDrawPixelsTexScaled(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f);
+ glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h,
+ int format, int type, int zoomfilter, void *rect,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y)
+{
+ glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
}
void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
@@ -580,17 +614,27 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
-void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
+void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h,
+ int format, int type, int zoomfilter, void *rect,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y)
{
if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) {
glColor4f(1.0, 1.0, 1.0, 1.0);
- glaDrawPixelsTex(x, y, img_w, img_h, format, type, zoomfilter, rect);
+ glaDrawPixelsTex_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
}
else {
glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect);
}
}
+void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
+{
+ glaDrawPixelsAuto_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
+ 0.0f, 0.0f, 0.0f, 0.0f);
+}
+
/* 2D Drawing Assistance */
void glaDefine2DArea(rcti *screen_rect)
@@ -795,8 +839,13 @@ void bglPolygonOffset(float viewdist, float dist)
#endif
}
else {
- /* should be clipping value or so... */
- offs = 0.0005f * dist;
+ /* This adjustment effectively results in reducing the Z value by 0.25%.
+ *
+ * winmat[14] actually evaluates to `-2 * far * near / (far - near)`,
+ * is very close to -0.2 with default clip range, and is used as the coefficient multiplied by `w / z`,
+ * thus controlling the z dependent part of the depth value.
+ */
+ offs = winmat[14] * -0.0025f * dist;
}
winmat[14] -= offs;
@@ -817,9 +866,11 @@ void bglPolygonOffset(float viewdist, float dist)
/* **** Color management helper functions for GLSL display/transform ***** */
/* Draw given image buffer on a screen using GLSL for display transform */
-void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
- ColorManagedViewSettings *view_settings,
- ColorManagedDisplaySettings *display_settings)
+void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
+ ColorManagedViewSettings *view_settings,
+ ColorManagedDisplaySettings *display_settings,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y)
{
bool force_fallback = false;
bool need_fallback = true;
@@ -869,14 +920,16 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
BLI_assert(!"Incompatible number of channels for GLSL display");
if (format != 0) {
- glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
- zoomfilter, ibuf->rect_float);
+ glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
+ zoomfilter, ibuf->rect_float,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
}
}
else if (ibuf->rect) {
/* ibuf->rect is always RGBA */
- glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
- zoomfilter, ibuf->rect);
+ glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
+ zoomfilter, ibuf->rect,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
}
IMB_colormanagement_finish_glsl_draw();
@@ -892,21 +945,43 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
- if (display_buffer)
- glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, display_buffer);
+ if (display_buffer) {
+ glaDrawPixelsAuto_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
+ zoomfilter, display_buffer,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
+ }
IMB_display_buffer_release(cache_handle);
}
}
-void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
+void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
+ ColorManagedViewSettings *view_settings,
+ ColorManagedDisplaySettings *display_settings)
+{
+ glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings,
+ 0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void glaDrawImBuf_glsl_ctx_clipping(const bContext *C,
+ ImBuf *ibuf,
+ float x, float y,
+ int zoomfilter,
+ float clip_min_x, float clip_min_y,
+ float clip_max_x, float clip_max_y)
{
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
- glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, view_settings, display_settings);
+ glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y);
+}
+
+void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
+{
+ glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f);
}
void cpack(unsigned int x)
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index cb07ce756a6..23c6aa37a83 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1064,17 +1064,11 @@ bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
/* screen sets cursor based on swinid */
static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
{
- ScrArea *sa = win->screen->areabase.first;
-
- for (; sa; sa = sa->next) {
- ARegion *ar = sa->regionbase.first;
- for (; ar; ar = ar->next) {
+ for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid == swinid) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
- if (ar->type && ar->type->cursor)
- ar->type->cursor(win, sa, ar);
- else
- WM_cursor_set(win, CURSOR_STD);
+ ED_region_cursor_set(win, sa, ar);
}
return;
}
@@ -1146,7 +1140,7 @@ void ED_screen_draw(wmWindow *win)
/* blended join arrow */
if (sa1 && sa2) {
int dir = area_getorientation(sa1, sa2);
- int dira;
+ int dira = -1;
if (dir != -1) {
switch (dir) {
case 0: /* W */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index be421d779eb..4111f67553a 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -3467,7 +3467,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if ((scene->audio.flag & AUDIO_SYNC) &&
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
- finite(time = BKE_sound_sync_scene(scene)))
+ isfinite(time = BKE_sound_sync_scene(scene)))
{
double newfra = (double)time * FPS;
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index a9cd601c9b0..88b3bc5d8fd 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -36,15 +36,12 @@
#include "MEM_guardedalloc.h"
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_threads.h"
+#include "BLT_translation.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -64,6 +61,7 @@
#include "BKE_paint.h"
#include "BKE_texture.h"
+#include "UI_interface.h"
#include "UI_view2d.h"
#include "ED_image.h"
@@ -498,8 +496,10 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
if (texpaint || (sima && sima->lock)) {
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
- /* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
+ if (w && h) {
+ /* Testing with partial update in uv editor too */
+ GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
+ }
}
}
@@ -1169,20 +1169,17 @@ typedef struct {
static void sample_color_update_header(SampleColorData *data, bContext *C)
{
-#define HEADER_LENGTH 150
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- BLI_snprintf(msg, HEADER_LENGTH,
- "Sample color for %s",
+ BLI_snprintf(msg, sizeof(msg),
+ IFACE_("Sample color for %s"),
!data->sample_palette ?
- "Brush. Use Left Click to sample for palette instead" :
- "Palette. Use Left Click to sample more colors");
+ IFACE_("Brush. Use Left Click to sample for palette instead") :
+ IFACE_("Palette. Use Left Click to sample more colors"));
ED_area_headerprint(sa, msg);
}
-
-#undef HEADER_LENGTH
}
static int sample_color_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index c5a066e9b14..080bd5b73c7 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -42,6 +42,7 @@
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
+#include "BLI_task.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -302,8 +303,8 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const
srcx = srcy = 0;
w = cache->tex_mask_old_w;
h = cache->tex_mask_old_h;
- destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
- desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
/* hack, use temporary rects so that clipping works */
IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
@@ -570,8 +571,8 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa
srcx = srcy = 0;
w = oldtexibuf->x;
h = oldtexibuf->y;
- destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
- desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
@@ -641,8 +642,8 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const
mapping->ymax = 1.0f;
}
else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0];
- mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1];
+ mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
+ mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
@@ -758,8 +759,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
}
else if (do_partial_update) {
/* do only partial update of texture */
- int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
- int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
+ int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
+ int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
if ((dx != 0) || (dy != 0)) {
brush_painter_imbuf_partial_update(painter, pos, diameter);
@@ -1019,6 +1020,64 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
+static void paint_2d_do_making_brush(ImagePaintState *s,
+ ImagePaintRegion *region,
+ unsigned short *curveb,
+ unsigned short *texmaskb,
+ ImBuf *frombuf,
+ float mask_max,
+ short blend,
+ int tilex, int tiley,
+ int tilew, int tileh)
+{
+ ImBuf tmpbuf;
+ IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
+ for (int ty = tiley; ty <= tileh; ty++) {
+ for (int tx = tilex; tx <= tilew; tx++) {
+ /* retrieve original pixels + mask from undo buffer */
+ unsigned short *mask;
+ int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
+ int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+
+ if (s->canvas->rect_float)
+ tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+ else
+ tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+
+ IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask,
+ curveb, texmaskb, mask_max,
+ region->destx, region->desty,
+ origx, origy,
+ region->srcx, region->srcy,
+ region->width, region->height,
+ blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
+ }
+ }
+}
+
+typedef struct Paint2DForeachData {
+ ImagePaintState *s;
+ ImagePaintRegion *region;
+ unsigned short *curveb;
+ unsigned short *texmaskb;
+ ImBuf *frombuf;
+ float mask_max;
+ short blend;
+ int tilex;
+ int tilew;
+} Paint2DForeachData;
+
+static void paint_2d_op_foreach_do(void *data_v, const int iter)
+{
+ Paint2DForeachData *data = (Paint2DForeachData *)data_v;
+ paint_2d_do_making_brush(data->s, data->region, data->curveb,
+ data->texmaskb, data->frombuf, data->mask_max,
+ data->blend,
+ data->tilex, iter,
+ data->tilew, iter);
+}
+
static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
@@ -1072,45 +1131,40 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
- int tilex, tiley, tilew, tileh, tx, ty;
- ImBuf *tmpbuf;
+ int tilex, tiley, tilew, tileh;
imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
region[a].width, region[a].height,
&tilex, &tiley, &tilew, &tileh);
- tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
-
- for (ty = tiley; ty <= tileh; ty++) {
- for (tx = tilex; tx <= tilew; tx++) {
- /* retrieve original pixels + mask from undo buffer */
- unsigned short *mask;
- int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
-
- if (s->canvas->rect_float)
- tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
- else
- tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
-
- IMB_rectblend(s->canvas, tmpbuf, frombuf, mask,
- curveb, texmaskb, mask_max,
- region[a].destx, region[a].desty,
- origx, origy,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
- }
+ if (tiley == tileh) {
+ paint_2d_do_making_brush(s, &region[a], curveb, texmaskb, frombuf,
+ mask_max, blend, tilex, tiley, tilew, tileh);
}
+ else {
+ Paint2DForeachData data;
+ data.s = s;
+ data.region = &region[a];
+ data.curveb = curveb;
+ data.texmaskb = texmaskb;
+ data.frombuf = frombuf;
+ data.mask_max = mask_max;
+ data.blend = blend;
+ data.tilex = tilex;
+ data.tilew = tilew;
+ BLI_task_parallel_range(tiley, tileh + 1, &data,
+ paint_2d_op_foreach_do,
+ true);
- IMB_freeImBuf(tmpbuf);
+ }
}
else {
/* no masking, composite brush directly onto canvas */
- IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
- region[a].destx, region[a].desty,
- region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend, false);
+ IMB_rectblend_threaded(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
+ region[a].destx, region[a].desty,
+ region[a].destx, region[a].desty,
+ region[a].srcx, region[a].srcy,
+ region[a].width, region[a].height, blend, false);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index b8693639673..d273f8320a1 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -107,6 +107,8 @@
#include "paint_intern.h"
+static void partial_redraw_array_init(ImagePaintPartialRedraw *pr);
+
/* Defines and Structs */
/* FTOCHAR as inline function */
BLI_INLINE unsigned char f_to_char(const float val)
@@ -1100,6 +1102,10 @@ static void uv_image_outset(
float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
const int ibuf_x, const int ibuf_y, const bool cw)
{
+ /* disallow shell-thickness to outset extreme values,
+ * otherwise near zero area UV's may extend thousands of pixels. */
+ const float scale_clamp = 5.0f;
+
float a1, a2, a3;
float puv[3][2]; /* pixelspace uv's */
float no1[2], no2[2], no3[2]; /* normals */
@@ -1150,6 +1156,10 @@ static void uv_image_outset(
a2 = shell_v2v2_normal_dir_to_dist(no2, dir1);
a3 = shell_v2v2_normal_dir_to_dist(no3, dir2);
+ CLAMP_MAX(a1, scale_clamp);
+ CLAMP_MAX(a2, scale_clamp);
+ CLAMP_MAX(a3, scale_clamp);
+
mul_v2_fl(no1, a1 * scaler);
mul_v2_fl(no2, a2 * scaler);
mul_v2_fl(no3, a3 * scaler);
@@ -3639,7 +3649,7 @@ static void project_paint_build_proj_ima(
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ partial_redraw_array_init(projIma->partRedrawRect);
projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
memset((void *)projIma->undoRect, 0, size);
projIma->maskRect = BLI_memarena_alloc(arena, size);
@@ -3990,8 +4000,8 @@ static void project_paint_end(ProjPaintState *ps)
/* 1 = an undo, -1 is a redo. */
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
{
- pr->x1 = 10000000;
- pr->y1 = 10000000;
+ pr->x1 = INT_MAX;
+ pr->y1 = INT_MAX;
pr->x2 = -1;
pr->y2 = -1;
@@ -5352,9 +5362,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
float lastpos[2] = {0.0, 0.0};
int a;
- for (a = 0; a < ps.image_tot; a++)
- partial_redraw_array_init(ps.projImages[a].partRedrawRect);
-
project_paint_op(&ps, lastpos, pos);
project_image_refresh_tagged(&ps);
@@ -5858,15 +5865,17 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
ED_mesh_uv_texture_ensure(me, NULL);
- BM_mesh_bm_from_me(bm, me, true, false, 0);
-
+ BM_mesh_bm_from_me(
+ bm, me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
ED_uvedit_unwrap_cube_project(ob, bm, 1.0, false);
/* set the margin really quickly before the packing operation*/
scene->toolsettings->uvcalc_margin = 0.001f;
ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
- BM_mesh_bm_to_me(bm, me, false);
+ BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm);
if (synch_selection)
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 42f0aaab173..27d3f6648a2 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -34,7 +34,7 @@
#include "DNA_userdef_types.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index bf751bfe74a..15ab4ca04a7 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2836,7 +2836,8 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
ViewContext *vc = &vpd->vc;
Object *ob = vc->obact;
-
+ Mesh *me = ob->data;
+
ED_vpaint_proj_handle_free(vpd->vp_handle);
MEM_freeN(vpd->indexar);
@@ -2847,6 +2848,7 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->mlooptag);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ DAG_id_tag_update(&me->id, 0);
MEM_freeN(vpd);
}
@@ -2979,7 +2981,7 @@ typedef struct DMGradient_userData {
const float *sco_end; /* [2] */
float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
int def_nr;
- short is_init;
+ bool is_init;
DMGradient_vertStore *vert_cache;
/* only for init */
BLI_bitmap *vert_visit;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 40ff662a2c2..c173156de3a 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -2997,7 +2997,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
const bool flip = (ss->cache->bstrength < 0);
const float radius = flip ? -ss->cache->radius : ss->cache->radius;
const float offset = get_offset(sd, ss);
- const float displace = radius * (0.25f + offset);;
+ const float displace = radius * (0.25f + offset);
float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
float area_no[3]; /* geometry normal */
@@ -5003,7 +5003,10 @@ void sculpt_dynamic_topology_enable(bContext *C)
/* Create triangles-only BMesh */
ss->bm = BM_mesh_create(&allocsize);
- BM_mesh_bm_from_me(ss->bm, me, true, true, ob->shapenr);
+ BM_mesh_bm_from_me(
+ ss->bm, me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true, .use_shapekey = true, .active_shapekey = ob->shapenr,
+ }));
sculpt_dynamic_topology_triangulate(ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index 839071d1330..24c3ee9cd3d 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -36,6 +36,7 @@ set(INC_SYS
)
set(SRC
+ action_buttons.c
action_data.c
action_draw.c
action_edit.c
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
new file mode 100644
index 00000000000..063a477d2b6
--- /dev/null
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -0,0 +1,132 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_action/action_buttons.c
+ * \ingroup spaction
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
+#include "BKE_unit.h"
+
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+
+#include "ED_anim_api.h"
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "action_intern.h" // own include
+
+/* ******************* action editor space & buttons ************** */
+
+/* ******************* general ******************************** */
+
+void action_buttons_register(ARegionType *UNUSED(art))
+{
+#if 0
+ PanelType *pt;
+
+ // TODO: AnimData / Actions List
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties");
+ strcpy(pt->idname, "ACTION_PT_properties");
+ strcpy(pt->label, N_("Active F-Curve"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = action_anim_panel_properties;
+ pt->poll = action_anim_panel_poll;
+ BLI_addtail(&art->paneltypes, pt);
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype action panel properties");
+ strcpy(pt->idname, "ACTION_PT_key_properties");
+ strcpy(pt->label, N_("Active Keyframe"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = action_anim_panel_key_properties;
+ pt->poll = action_anim_panel_poll;
+ BLI_addtail(&art->paneltypes, pt);
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers");
+ strcpy(pt->idname, "ACTION_PT_modifiers");
+ strcpy(pt->label, N_("Modifiers"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = action_anim_panel_modifiers;
+ pt->poll = action_anim_panel_poll;
+ BLI_addtail(&art->paneltypes, pt);
+#endif
+}
+
+static int action_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = action_has_buttons_region(sa);
+
+ if (ar)
+ ED_region_toggle_hidden(C, ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_properties(wmOperatorType *ot)
+{
+ ot->name = "Properties";
+ ot->idname = "ACTION_OT_properties";
+ ot->description = "Toggle display properties panel";
+
+ ot->exec = action_properties_toggle_exec;
+ ot->poll = ED_operator_action_active;
+
+ /* flags */
+ ot->flag = 0;
+}
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index c66028b17fc..c0947dacbf0 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -239,6 +239,11 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
}
}
+ if (fabsf(*max - *min) < 0.001f) {
+ *min -= 0.0005f;
+ *max += 0.0005f;
+ }
+
/* free memory */
ANIM_animdata_freelist(&anim_data);
}
@@ -431,13 +436,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
return actkeys_viewall(C, true);
}
-static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
-{
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- ANIM_center_frame(C, smooth_viewtx);
-
- return OPERATOR_FINISHED;
-}
+/* ......... */
void ACTION_OT_view_all(wmOperatorType *ot)
{
@@ -469,17 +468,27 @@ void ACTION_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** View-All Operator ****************** */
+
+static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
void ACTION_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
ot->name = "View Frame";
ot->idname = "ACTION_OT_view_frame";
ot->description = "Reset viewable area to show range around current frame";
-
+
/* api callbacks */
ot->exec = actkeys_view_frame_exec;
- ot->poll = ED_operator_action_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
-
+ ot->poll = ED_operator_action_active;
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -496,7 +505,7 @@ static short copy_action_keys(bAnimContext *ac)
int filter, ok = 0;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 17f1f404225..50e10e7e154 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -34,11 +34,21 @@
struct bContext;
struct bAnimContext;
struct SpaceAction;
+struct ScrArea;
struct ARegion;
+struct ARegionType;
struct wmOperatorType;
/* internal exports only */
+/* **************************************** */
+/* space_action.c / action_buttons.c */
+
+struct ARegion *action_has_buttons_region(struct ScrArea *sa);
+
+void action_buttons_register(struct ARegionType *art);
+void ACTION_OT_properties(struct wmOperatorType *ot);
+
/* ***************************************** */
/* action_draw.c */
void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *ar);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index 59b147c6f6c..f69f9944f8a 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -51,6 +51,9 @@
void action_operatortypes(void)
{
+ /* view */
+ WM_operatortype_append(ACTION_OT_properties);
+
/* keyframes */
/* selection */
WM_operatortype_append(ACTION_OT_clickselect);
@@ -257,6 +260,13 @@ void action_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ /* keymap for all regions */
+ keymap = WM_keymap_find(keyconf, "Dopesheet Generic", SPACE_ACTION, 0);
+
+ /* region management... */
+ WM_keymap_add_item(keymap, "ACTION_OT_properties", NKEY, KM_PRESS, 0, 0);
+
+
/* channels */
/* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module.
* All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 53c5a008af8..60240109432 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -59,6 +59,32 @@
#include "action_intern.h" /* own include */
+/* ******************** manage regions ********************* */
+
+ARegion *action_has_buttons_region(ScrArea *sa)
+{
+ ARegion *ar, *arnew;
+
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ if (ar) return ar;
+
+ /* add subdiv level; after main */
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+
+ /* is error! */
+ if (ar == NULL) return NULL;
+
+ arnew = MEM_callocN(sizeof(ARegion), "buttons for action");
+
+ BLI_insertlinkafter(&sa->regionbase, ar, arnew);
+ arnew->regiontype = RGN_TYPE_UI;
+ arnew->alignment = RGN_ALIGN_RIGHT;
+
+ arnew->flag = RGN_FLAG_HIDDEN;
+
+ return arnew;
+}
+
/* ******************** default callbacks for action space ***************** */
static SpaceLink *action_new(const bContext *C)
@@ -93,6 +119,14 @@ static SpaceLink *action_new(const bContext *C)
ar->v2d.scroll = V2D_SCROLL_BOTTOM;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
+ /* ui buttons */
+ ar = MEM_callocN(sizeof(ARegion), "buttons region for action");
+
+ BLI_addtail(&saction->regionbase, ar);
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_RIGHT;
+ ar->flag = RGN_FLAG_HIDDEN;
+
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for action");
@@ -159,6 +193,8 @@ static void action_main_region_init(wmWindowManager *wm, ARegion *ar)
/* own keymap */
keymap = WM_keymap_find(wm->defaultconf, "Dopesheet", SPACE_ACTION, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+ keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
}
static void action_main_region_draw(const bContext *C, ARegion *ar)
@@ -231,6 +267,9 @@ static void action_channel_region_init(wmWindowManager *wm, ARegion *ar)
/* own keymap */
keymap = WM_keymap_find(wm->defaultconf, "Animation Channels", 0, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
}
static void action_channel_region_draw(const bContext *C, ARegion *ar)
@@ -498,6 +537,54 @@ static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
}
+/* add handlers, stuff you only do once or on area/region changes */
+static void action_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
+
+ ED_region_panels_init(wm, ar);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+}
+
+static void action_buttons_area_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar, NULL, -1, true);
+}
+
+static void action_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_ANIMATION:
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SCENE:
+ switch (wmn->data) {
+ case ND_OB_ACTIVE:
+ case ND_FRAME:
+ case ND_MARKERS:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
+ case NC_OBJECT:
+ switch (wmn->data) {
+ case ND_BONE_ACTIVE:
+ case ND_BONE_SELECT:
+ case ND_KEYS:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
+ default:
+ if (wmn->data == ND_KEYS)
+ ED_region_tag_redraw(ar);
+ break;
+ }
+}
+
static void action_refresh(const bContext *C, ScrArea *sa)
{
SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
@@ -579,6 +666,18 @@ void ED_spacetype_action(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: UI buttons */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
+ art->regionid = RGN_TYPE_UI;
+ art->prefsizex = 200;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->listener = action_region_listener;
+ art->init = action_buttons_area_init;
+ art->draw = action_buttons_area_draw;
+
+ BLI_addhead(&st->regiontypes, art);
+
+ action_buttons_register(art);
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 182f2bd2e80..97a85bce006 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -27,10 +27,6 @@
#include <string.h>
#include <stdio.h>
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 207879c2809..8e1f781827a 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1426,7 +1426,7 @@ int filelist_files_ensure(FileList *filelist)
filelist_filter(filelist);
}
- return filelist->filelist.nbr_entries_filtered;;
+ return filelist->filelist.nbr_entries_filtered;
}
static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 981b101519c..bf90a4ea170 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -242,7 +242,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if (params->display == FILE_DEFAULTDISPLAY) {
if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE))
+ if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT))
params->display = FILE_IMGDISPLAY;
else
params->display = FILE_SHORTDISPLAY;
@@ -477,7 +477,7 @@ static void column_widths(FileSelectParams *params, struct FileLayout *layout)
layout->column_widths[i] = 0;
}
- layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;;
+ layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
/* Biggest possible reasonable values... */
layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89");
layout->column_widths[COLUMN_TIME] = file_string_width("23:59");
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index e77f545fbc0..7fb294529c9 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -225,7 +225,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
filelist_setsorting(sfile->files, params->sort);
filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0,
false, /* TODO hide_parent, should be controllable? */
- params->flag & FILE_FILTER ? params->filter : 0,
+ (params->flag & FILE_FILTER) ? params->filter : 0,
params->filter_id,
params->filter_glob,
params->filter_search);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 39b17410e62..a9ab1502e16 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -516,7 +516,7 @@ static void driver_delete_var_cb(bContext *UNUSED(C), void *driver_v, void *dvar
DriverVar *dvar = (DriverVar *)dvar_v;
/* remove the active variable */
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
}
/* callback to report why a driver variable is invalid */
@@ -607,6 +607,7 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
}
/* settings for 'rotation difference' driver variable type */
+/* FIXME: 1) Must be same armature for both dtars, 2) Alignment issues... */
static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
{
DriverTarget *dtar = &dvar->targets[0];
@@ -623,7 +624,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Bone 1"), ICON_NONE);
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
@@ -634,7 +635,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Bone 2"), ICON_NONE);
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
@@ -661,13 +662,13 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
- uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
@@ -675,13 +676,13 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
-
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
+
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
- uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
@@ -702,13 +703,13 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
/* properties */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
- uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
sub = uiLayoutColumn(layout, true);
@@ -825,34 +826,59 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
uiItemL(row, valBuf, ICON_NONE);
}
- /* add driver variables */
- col = uiLayoutColumn(pa->layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
- 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0, 0,
- TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
- UI_but_func_set(but, driver_add_var_cb, driver, NULL);
+ /* add/copy/paste driver variables */
+ {
+ uiLayout *row;
+
+ /* add driver variable */
+ row = uiLayoutRow(pa->layout, false);
+ block = uiLayoutGetBlock(row);
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, 0,
+ TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
+ UI_but_func_set(but, driver_add_var_cb, driver, NULL);
+
+ /* copy/paste (as sub-row) */
+ row = uiLayoutRow(row, true);
+ block = uiLayoutGetBlock(row);
+
+ uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy");
+ uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste");
+ }
/* loop over targets, drawing them */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
PointerRNA dvar_ptr;
uiLayout *box, *row;
+ uiLayout *subrow, *sub;
/* sub-layout column for this variable's settings */
col = uiLayoutColumn(pa->layout, true);
- /* header panel */
+ /* 1) header panel */
box = uiLayoutBox(col);
- /* first row context info for driver */
RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
row = uiLayoutRow(box, false);
block = uiLayoutGetBlock(row);
- /* variable name */
- uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
- /* invalid name? */
+ /* 1.1) variable type and name */
+ subrow = uiLayoutRow(row, true);
+
+ /* 1.1.1) variable type */
+ sub = uiLayoutRow(subrow, true); /* HACK: special group just for the enum, otherwise we */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); /* we get ugly layout with text included too... */
+
+ uiItemR(sub, &dvar_ptr, "type", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+
+ /* 1.1.2) variable name */
+ sub = uiLayoutRow(subrow, true); /* HACK: special group to counteract the effects of the previous */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_EXPAND); /* enum, which now pushes everything too far right */
+
+ uiItemR(sub, &dvar_ptr, "name", 0, "", ICON_NONE);
+
+ /* 1.2) invalid name? */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
if (dvar->flag & DVAR_FLAG_INVALID_NAME) {
@@ -861,17 +887,14 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
UI_but_func_set(but, driver_dvar_invalid_name_query_cb, dvar, NULL); // XXX: reports?
}
- /* remove button */
+ /* 1.3) remove button */
but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
UI_block_emboss_set(block, UI_EMBOSS);
- /* variable type */
- row = uiLayoutRow(box, false);
- uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
-
- /* variable type settings */
+
+ /* 2) variable type settings */
box = uiLayoutBox(col);
/* controls to draw depends on the type of variable */
switch (dvar->type) {
@@ -889,7 +912,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
break;
}
- /* value of variable */
+ /* 3) value of variable */
if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
char valBuf[32];
@@ -948,15 +971,13 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
/* 'add modifier' button at top of panel */
{
row = uiLayoutRow(pa->layout, false);
- block = uiLayoutGetBlock(row);
/* this is an operator button which calls a 'add modifier' operator...
* a menu might be nicer but would be tricky as we need some custom filtering
*/
- uiDefButO(block, UI_BTYPE_BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"),
- 0.5 * UI_UNIT_X, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, TIP_("Adds a new F-Curve Modifier for the active F-Curve"));
+ uiItemMenuEnumO(row, (bContext *)C, "GRAPH_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
- /* copy/paste (as sub-row)*/
+ /* copy/paste (as sub-row) */
row = uiLayoutRow(row, true);
uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
@@ -970,7 +991,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
}
-
+
MEM_freeN(ale);
}
@@ -980,14 +1001,6 @@ void graph_buttons_register(ARegionType *art)
{
PanelType *pt;
- pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
- strcpy(pt->idname, "GRAPH_PT_view");
- strcpy(pt->label, N_("View Properties"));
- strcpy(pt->category, "View");
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = graph_panel_view;
- BLI_addtail(&art->paneltypes, pt);
-
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_properties");
strcpy(pt->label, N_("Active F-Curve"));
@@ -1024,6 +1037,14 @@ void graph_buttons_register(ARegionType *art)
pt->draw = graph_panel_modifiers;
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
+ strcpy(pt->idname, "GRAPH_PT_view");
+ strcpy(pt->label, N_("View Properties"));
+ strcpy(pt->category, "View");
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = graph_panel_view;
+ BLI_addtail(&art->paneltypes, pt);
}
static int graph_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 10baed8508d..f1063996ca3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -54,6 +54,7 @@
#include "BLT_translation.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -264,13 +265,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
}
-static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
-{
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- ANIM_center_frame(C, smooth_viewtx);
- return OPERATOR_FINISHED;
-}
-
+/* ......... */
void GRAPH_OT_view_all(wmOperatorType *ot)
{
@@ -310,17 +305,26 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
+/* ********************** View Frame Operator ****************************** */
+
+static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
void GRAPH_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
ot->name = "View Frame";
ot->idname = "GRAPH_OT_view_frame";
ot->description = "Reset viewable area to show range around current frame";
-
+
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
- ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
-
+ ot->poll = ED_operator_graphedit_active;
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -689,6 +693,14 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
short mapping_flag = ANIM_get_normalization_flags(&ac);
float scale, offset;
+ /* preserve selection? */
+ if (RNA_boolean_get(op->ptr, "extend") == false) {
+ /* deselect all keyframes first, so that we can immediately start manipulating the newly added one(s)
+ * - only affect the keyframes themselves, as we don't want channels popping in and out...
+ */
+ deselect_graph_keys(&ac, false, SELECT_SUBTRACT, false);
+ }
+
/* get frame and value from props */
frame = RNA_float_get(op->ptr, "frame");
val = RNA_float_get(op->ptr, "value");
@@ -778,6 +790,8 @@ void GRAPH_OT_click_insert(wmOperatorType *ot)
/* properties */
RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100);
RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
+
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
}
/* ******************** Copy/Paste Keyframes Operator ************************* */
@@ -789,7 +803,7 @@ static short copy_graph_keys(bAnimContext *ac)
int filter, ok = 0;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
@@ -2374,27 +2388,29 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p
EnumPropertyItem *item = NULL;
int totitem = 0;
int i = 0;
-
+
if (C == NULL) {
return rna_enum_fmodifier_type_items;
}
-
+
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
int index;
-
+
/* check if modifier is valid for this context */
if (fmi == NULL)
continue;
-
+
index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type);
- RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
+ if (index != -1) { /* Not all types are implemented yet... */
+ RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
+ }
}
-
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -2435,16 +2451,15 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
break;
}
-
+
ale->update |= ANIM_UPDATE_DEPS;
}
-
+
ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
- // FIXME: this really isn't the best description for it...
- WM_event_add_notifier(C, NC_ANIMATION, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -2452,11 +2467,11 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
{
PropertyRNA *prop;
-
+
/* identifiers */
ot->name = "Add F-Curve Modifier";
ot->idname = "GRAPH_OT_fmodifier_add";
- ot->description = "Add F-Modifiers to the selected F-Curves";
+ ot->description = "Add F-Modifier to the active/selected F-Curves";
/* api callbacks */
ot->invoke = WM_menu_invoke;
@@ -2470,7 +2485,7 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
RNA_def_enum_funcs(prop, graph_fmodifier_itemf);
ot->prop = prop;
-
+
RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve");
}
@@ -2487,7 +2502,7 @@ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* clear buffer first */
- free_fmodifiers_copybuf();
+ ANIM_fmodifiers_copybuf_free();
/* get the active F-Curve */
ale = get_active_fcurve_channel(&ac);
@@ -2495,10 +2510,10 @@ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
/* if this exists, call the copy F-Modifiers API function */
if (ale && ale->data) {
FCurve *fcu = (FCurve *)ale->data;
-
+
/* TODO: when 'active' vs 'all' boolean is added, change last param! */
ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0);
-
+
/* free temp data now */
MEM_freeN(ale);
}
@@ -2535,33 +2550,43 @@ void GRAPH_OT_fmodifier_copy(wmOperatorType *ot)
static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter, ok = 0;
+ int filter;
+
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+ bool ok = false;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ if (RNA_boolean_get(op->ptr, "only_active")) {
+ /* This should be the default (for buttons) - Just paste to the active FCurve */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ }
+ else {
+ /* This is only if the operator gets called from a hotkey or search - Paste to all visible curves */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ }
+
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* paste modifiers */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->data;
int tot;
-
- /* TODO: do we want to replace existing modifiers? add user pref for that! */
- tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
-
+
+ tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace);
+
if (tot) {
ale->update |= ANIM_UPDATE_DEPS;
+ ok = true;
}
-
- ok += tot;
}
-
+
if (ok) {
ANIM_animdata_update(&ac, &anim_data);
}
@@ -2569,7 +2594,6 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* successful or not? */
if (ok) {
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2594,6 +2618,128 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active F-Curve");
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
+}
+
+/* ************************************************************************** */
+/* Drivers */
+
+/* ******************** Copy Driver Vars Operator *********************** */
+
+static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ bAnimListElem *ale;
+ bool ok = false;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* clear buffer first */
+ ANIM_driver_vars_copybuf_free();
+
+ /* get the active F-Curve */
+ ale = get_active_fcurve_channel(&ac);
+
+ /* if this exists, call the copy driver vars API function */
+ if (ale && ale->data) {
+ FCurve *fcu = (FCurve *)ale->data;
+
+ ok = ANIM_driver_vars_copy(op->reports, fcu);
+
+ /* free temp data now */
+ MEM_freeN(ale);
+ }
+
+ /* successful or not? */
+ if (ok)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void GRAPH_OT_driver_variables_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Driver Variables";
+ ot->idname = "GRAPH_OT_driver_variables_copy";
+ ot->description = "Copy the driver variables of the active F-Curve";
+
+ /* api callbacks */
+ ot->exec = graph_driver_vars_copy_exec;
+ ot->poll = graphop_active_fcurve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************** Paste Driver Vars Operator *********************** */
+
+static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+ bool ok = false;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* paste variables */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->data;
+ ok |= ANIM_driver_vars_paste(op->reports, fcu, replace);
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* successful or not? */
+ if (ok) {
+ /* rebuild depsgraph, now that there are extra deps here */
+ DAG_relations_tag_update(CTX_data_main(C));
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C));
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GRAPH_OT_driver_variables_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Paste Driver Variables";
+ ot->idname = "GRAPH_OT_driver_variables_paste";
+ ot->description = "Add copied driver variables to the active driver";
+
+ /* api callbacks */
+ ot->exec = graph_driver_vars_paste_exec;
+ ot->poll = graphop_active_fcurve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing driver variables, instead of just appending to the end of the existing list");
}
/* ************************************************************************** */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index a478a86a5e2..534b712fd5e 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -56,6 +56,8 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str
/* ***************************************** */
/* graph_select.c */
+void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels);
+
void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot);
void GRAPH_OT_select_border(struct wmOperatorType *ot);
void GRAPH_OT_select_lasso(struct wmOperatorType *ot);
@@ -148,6 +150,11 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot);
/* ----------- */
+void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot);
+void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot);
+
+/* ----------- */
+
void GRAPH_OT_ghost_curves_create(struct wmOperatorType *ot);
void GRAPH_OT_ghost_curves_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 59215531ac0..6b860990c10 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -458,6 +458,10 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_fmodifier_add);
WM_operatortype_append(GRAPH_OT_fmodifier_copy);
WM_operatortype_append(GRAPH_OT_fmodifier_paste);
+
+ /* Drivers */
+ WM_operatortype_append(GRAPH_OT_driver_variables_copy);
+ WM_operatortype_append(GRAPH_OT_driver_variables_paste);
}
void ED_operatormacros_graph(void)
@@ -606,7 +610,11 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* insertkey */
WM_keymap_add_item(keymap, "GRAPH_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "extend", false);
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", true);
/* copy/paste */
WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 67274100312..eb786d872ec 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -83,7 +83,7 @@
* 2 = invert
* - do_channels: whether to affect selection status of channels
*/
-static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels)
+void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channels)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index f22152651e2..a2db6827b0e 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -177,7 +177,7 @@ void image_preview_event(int event)
G.is_break = false;
G.scene->nodetree->timecursor = set_timecursor;
- G.scene->nodetree->test_break = blender_test_break;
+ G.scene->nodetree->test_break = BKE_blender_test_break;
BIF_store_spare();
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 0ddbb1153c0..e810f4db7dd 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -197,6 +197,19 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
dx += BLF_width(blf_mono_font, str, sizeof(str));
}
+ if (channels == 1 && (cp != NULL || fp != NULL)) {
+ if (fp != NULL) {
+ BLI_snprintf(str, sizeof(str), " Val:%-.3f |", fp[0]);
+ }
+ else if (cp != NULL) {
+ BLI_snprintf(str, sizeof(str), " Val:%-.3f |", cp[0] / 255.0f);
+ }
+ glColor3ub(255, 255, 255);
+ BLF_position(blf_mono_font, dx, dy, 0);
+ BLF_draw_ascii(blf_mono_font, str, sizeof(str));
+ dx += BLF_width(blf_mono_font, str, sizeof(str));
+ }
+
if (channels >= 3) {
glColor3ubv(red);
if (fp)
@@ -526,7 +539,12 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
}
if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) == 0) {
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ int clip_max_x, clip_max_y;
+ UI_view2d_view_to_region(&ar->v2d,
+ ar->v2d.cur.xmax, ar->v2d.cur.ymax,
+ &clip_max_x, &clip_max_y);
+ glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, GL_NEAREST,
+ 0, 0, clip_max_x, clip_max_y);
}
else {
unsigned char *display_buffer;
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 3b57d17f9f3..69993c3be65 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -63,6 +63,7 @@ void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot);
+void IMAGE_OT_view_zoom_border(struct wmOperatorType *ot);
void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
void IMAGE_OT_new(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index eb74922a256..8db5a8f9bd3 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -149,6 +149,34 @@ static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac, c
sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
}
+/**
+ * Fits the view to the bounds exactly, caller should add margin if needed.
+ */
+static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf *bounds)
+{
+ int image_size[2];
+ float aspx, aspy;
+
+ ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
+ ED_space_image_get_aspect(sima, &aspx, &aspy);
+
+ image_size[0] = image_size[0] * aspx;
+ image_size[1] = image_size[1] * aspy;
+
+ /* adjust offset and zoom */
+ sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
+ sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
+
+ float size_xy[2], size;
+ size_xy[0] = BLI_rcti_size_x(&ar->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
+ size_xy[1] = BLI_rcti_size_y(&ar->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
+
+ size = min_ff(size_xy[0], size_xy[1]);
+ CLAMP_MAX(size, 100.0f);
+
+ sima_zoom_set(sima, ar, size, NULL);
+}
+
#if 0 // currently unused
static int image_poll(bContext *C)
{
@@ -763,8 +791,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene;
Object *obedit;
Image *ima;
- float size, min[2], max[2], d[2], aspx, aspy;
- int width, height;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -773,33 +799,28 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
obedit = CTX_data_edit_object(C);
ima = ED_space_image(sima);
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_aspect(sima, &aspx, &aspy);
-
- width = width * aspx;
- height = height * aspy;
/* get bounds */
+ float min[2], max[2];
if (ED_space_image_show_uvedit(sima, obedit)) {
- if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
+ if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
return OPERATOR_CANCELLED;
+ }
}
else if (ED_space_image_check_show_maskedit(scene, sima)) {
if (!ED_mask_selected_minmax(C, min, max)) {
return OPERATOR_CANCELLED;
}
}
+ rctf bounds = {
+ .xmin = min[0], .ymin = min[1],
+ .xmax = max[0], .ymax = max[1],
+ };
- /* adjust offset and zoom */
- sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width);
- sima->yof = (int)(((min[1] + max[1]) * 0.5f - 0.5f) * height);
+ /* add some margin */
+ BLI_rctf_scale(&bounds, 1.4f);
- d[0] = max[0] - min[0];
- d[1] = max[1] - min[1];
- size = 0.5f * MAX2(d[0], d[1]) * MAX2(width, height) / 256.0f;
-
- if (size <= 0.01f) size = 0.01f;
- sima_zoom_set(sima, ar, 0.7f / size, NULL);
+ sima_zoom_set_from_bounds(sima, ar, &bounds);
ED_region_tag_redraw(ar);
@@ -969,6 +990,62 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
"Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
}
+/********************** view border-zoom operator *********************/
+
+static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+ rctf bounds;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+
+ WM_operator_properties_border_to_rctf(op, &bounds);
+
+ UI_view2d_region_to_view_rctf(&ar->v2d, &bounds, &bounds);
+
+ const struct {
+ float xof;
+ float yof;
+ float zoom;
+ } sima_view_prev = {
+ .xof = sima->xof,
+ .yof = sima->yof,
+ .zoom = sima->zoom,
+ };
+
+ sima_zoom_set_from_bounds(sima, ar, &bounds);
+
+ /* zoom out */
+ if (gesture_mode == GESTURE_MODAL_OUT) {
+ sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
+ sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
+ sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Zoom to Border";
+ ot->description = "Zoom in the view to the nearest item contained in the border";
+ ot->idname = "IMAGE_OT_view_zoom_border";
+
+ /* api callbacks */
+ ot->invoke = WM_border_select_invoke;
+ ot->exec = image_view_zoom_border_exec;
+ ot->modal = WM_border_select_modal;
+ ot->cancel = WM_border_select_cancel;
+
+ ot->poll = space_image_main_region_poll;
+
+ /* rna */
+ WM_operator_properties_gesture_border(ot, false);
+}
+
/**************** load/replace/save callbacks ******************/
static void image_filesel(bContext *C, wmOperator *op, const char *path)
{
@@ -2749,8 +2826,8 @@ typedef struct ImageSampleInfo {
int *zp;
float *zfp;
- int draw;
- int color_manage;
+ bool draw;
+ bool color_manage;
int use_default_view;
} ImageSampleInfo;
@@ -2824,7 +2901,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf == NULL) {
ED_space_image_release_buffer(sima, ibuf, lock);
- info->draw = 0;
+ info->draw = false;
return;
}
@@ -2841,7 +2918,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
info->x = x;
info->y = y;
- info->draw = 1;
+ info->draw = true;
info->channels = ibuf->channels;
info->colp = NULL;
@@ -2874,10 +2951,24 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf->rect_float) {
fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
- info->colf[0] = fp[0];
- info->colf[1] = fp[1];
- info->colf[2] = fp[2];
- info->colf[3] = fp[3];
+ if (ibuf->channels == 4) {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = fp[3];
+ }
+ else if (ibuf->channels == 3) {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = 1.0f;
+ }
+ else {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[0];
+ info->colf[2] = fp[0];
+ info->colf[3] = 1.0f;
+ }
info->colfp = info->colf;
copy_v4_v4(info->linearcol, info->colf);
@@ -2888,10 +2979,16 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf->zbuf) {
info->z = ibuf->zbuf[y * ibuf->x + x];
info->zp = &info->z;
+ if (ibuf->zbuf == (int*)ibuf->rect) {
+ info->colp = NULL;
+ }
}
if (ibuf->zbuf_float) {
info->zf = ibuf->zbuf_float[y * ibuf->x + x];
info->zfp = &info->zf;
+ if (ibuf->zbuf_float == ibuf->rect_float) {
+ info->colfp = NULL;
+ }
}
if (curve_mapping && ibuf->channels == 4) {
@@ -3140,7 +3237,7 @@ static int image_record_composite_apply(bContext *C, wmOperator *op)
WM_cursor_time(CTX_wm_window(C), scene->r.cfra);
- // XXX scene->nodetree->test_break = blender_test_break;
+ // XXX scene->nodetree->test_break = BKE_blender_test_break;
// XXX scene->nodetree->test_break = NULL;
BKE_image_all_free_anim_ibufs(scene->r.cfra);
@@ -3554,7 +3651,7 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
void IMAGE_OT_clear_render_border(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Render Border";
+ ot->name = "Clear Render Border";
ot->description = "Clear the boundaries of the border render and disable border render";
ot->idname = "IMAGE_OT_clear_render_border";
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ccf9e825e1b..168f9c0dfdf 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -232,6 +232,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_zoom_in);
WM_operatortype_append(IMAGE_OT_view_zoom_out);
WM_operatortype_append(IMAGE_OT_view_zoom_ratio);
+ WM_operatortype_append(IMAGE_OT_view_zoom_border);
WM_operatortype_append(IMAGE_OT_view_ndof);
WM_operatortype_append(IMAGE_OT_new);
@@ -303,6 +304,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0);
/* ctrl now works as well, shift + numpad works as arrow keys on Windows */
RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index dafb71b4480..8dc6c4229b2 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -44,7 +44,7 @@
#include "BLT_translation.h"
#include "BKE_anim.h"
-#include "BKE_blender.h"
+#include "BKE_blender_version.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_DerivedMesh.h"
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 5f046e3b6c6..cbdc476bee6 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -478,12 +478,10 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
row = uiLayoutRow(pa->layout, false);
block = uiLayoutGetBlock(row);
- // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
- uiDefButO(block, UI_BTYPE_BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"), 10, 0, UI_UNIT_X * 7.0f, UI_UNIT_Y,
- TIP_("Adds a new F-Modifier for the active NLA Strip"));
+ uiItemMenuEnumO(row, (bContext *)C, "NLA_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
- /* copy/paste (as sub-row)*/
+ /* copy/paste (as sub-row) */
row = uiLayoutRow(row, true);
uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste");
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index ff71cc47158..a2159696394 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -542,6 +542,30 @@ void NLA_OT_view_selected(wmOperatorType *ot)
}
/* *********************************************** */
+
+static int nlaedit_viewframe_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
+void NLA_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "NLA_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = nlaedit_viewframe_exec;
+ ot->poll = ED_operator_nla_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************************************** */
/* NLA Editing Operations (Constructive/Destructive) */
/* ******************** Add Action-Clip Operator ***************************** */
@@ -2213,19 +2237,20 @@ void NLA_OT_snap(wmOperatorType *ot)
/* ******************** Add F-Modifier Operator *********************** */
-/* present a special customised popup menu for this, with some filtering */
-static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+static EnumPropertyItem *nla_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
- uiPopupMenu *pup;
- uiLayout *layout;
- int i;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+ int i = 0;
- pup = UI_popup_menu_begin(C, IFACE_("Add F-Modifier"), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
+ if (C == NULL) {
+ return rna_enum_fmodifier_type_items;
+ }
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ int index;
/* check if modifier is valid for this context */
if (fmi == NULL)
@@ -2233,16 +2258,19 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
continue;
- /* add entry to add this type of modifier */
- uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
+ index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type);
+ if (index != -1) { /* Not all types are implemented yet... */
+ RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
+ }
}
- uiItemS(layout);
- UI_popup_menu_end(C, pup);
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
- return OPERATOR_INTERFACE;
+ return item;
}
+
static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -2316,10 +2344,10 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add F-Modifier";
ot->idname = "NLA_OT_fmodifier_add";
- ot->description = "Add a F-Modifier of the specified type to the selected NLA-Strips";
+ ot->description = "Add F-Modifier to the active/selected NLA-Strips";
/* api callbacks */
- ot->invoke = nla_fmodifier_add_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = nla_fmodifier_add_exec;
ot->poll = nlaop_poll_tweakmode_off;
@@ -2328,7 +2356,9 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
/* id-props */
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
- RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
+ RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf);
+
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
}
/* ******************** Copy F-Modifiers Operator *********************** */
@@ -2346,7 +2376,7 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* clear buffer first */
- free_fmodifiers_copybuf();
+ ANIM_fmodifiers_copybuf_free();
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
@@ -2408,12 +2438,15 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
bAnimListElem *ale;
int filter, ok = 0;
+ const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2422,8 +2455,20 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
NlaStrip *strip;
for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: do we want to replace existing modifiers? add user pref for that!
- ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
+ /* can F-Modifier be added to the current strip? */
+ if (active_only) {
+ /* if not active, cannot add since we're only adding to active strip */
+ if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
+ continue;
+ }
+ else {
+ /* strip must be selected, since we're not just doing active */
+ if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
+ continue;
+ }
+
+ /* paste FModifiers from buffer */
+ ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, replace);
ale->update |= ANIM_UPDATE_DEPS;
}
}
@@ -2456,6 +2501,11 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip");
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
}
/* *********************************************** */
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 344580c0d15..806fbe90ff2 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -94,6 +94,7 @@ void NLA_OT_previewrange_set(wmOperatorType *ot);
void NLA_OT_view_all(wmOperatorType *ot);
void NLA_OT_view_selected(wmOperatorType *ot);
+void NLA_OT_view_frame(wmOperatorType *ot);
void NLA_OT_actionclip_add(wmOperatorType *ot);
void NLA_OT_transition_add(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 98da10470f8..386950ead3a 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -130,6 +130,7 @@ void nla_operatortypes(void)
/* view */
WM_operatortype_append(NLA_OT_view_all);
WM_operatortype_append(NLA_OT_view_selected);
+ WM_operatortype_append(NLA_OT_view_frame);
WM_operatortype_append(NLA_OT_previewrange_set);
@@ -243,6 +244,7 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "NLA_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "NLA_OT_view_frame", PAD0, KM_PRESS, 0, 0);
/* editing ------------------------------------------------ */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index b2f3306fb62..ddbd07616bc 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1953,6 +1953,7 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 07e79c5a59c..d7249897723 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -107,7 +107,7 @@ static bool node_group_has_output_dfs(bNode *node)
current_node = current_node->next)
{
if (current_node->type == NODE_GROUP) {
- if (node_group_has_output_dfs(current_node)) {
+ if (current_node->id && node_group_has_output_dfs(current_node)) {
return true;
}
}
@@ -514,12 +514,10 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
-#define HEADER_LENGTH 256
- char header[HEADER_LENGTH];
+ char header[UI_MAX_DRAW_STR];
- BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), HEADER_LENGTH);
+ BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), sizeof(header));
ED_area_headerprint(CTX_wm_area(C), header);
-#undef HEADER_LENGTH
}
static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 0cbb7ea0220..09594ab543c 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -32,6 +32,7 @@
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
+#include "BLI_array.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -420,6 +421,13 @@ static int ui_compatible_sockets(int typeA, int typeB)
return (typeA == typeB);
}
+static int ui_node_item_name_compare(const void *a, const void *b)
+{
+ const bNodeType *type_a = *(const bNodeType **)a;
+ const bNodeType *type_b = *(const bNodeType **)b;
+ return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
+}
+
static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
{
bNodeTree *ntree = arg->ntree;
@@ -439,7 +447,26 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
compatibility = NODE_OLD_SHADING;
}
+ /* generate array of node types sorted by UI name */
+ bNodeType **sorted_ntypes = NULL;
+ BLI_array_declare(sorted_ntypes);
+
NODE_TYPES_BEGIN(ntype) {
+ if (compatibility && !(ntype->compatibility & compatibility))
+ continue;
+
+ if (ntype->nclass != nclass)
+ continue;
+
+ BLI_array_append(sorted_ntypes, ntype);
+ }
+ NODE_TYPES_END
+
+ qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
+
+ /* generate UI */
+ for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) {
+ bNodeType *ntype = sorted_ntypes[j];
NodeLinkItem *items;
int totitems;
char name[UI_MAX_NAME_STR];
@@ -447,12 +474,6 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
int i, num = 0;
int icon = ICON_NONE;
- if (compatibility && !(ntype->compatibility & compatibility))
- continue;
-
- if (ntype->nclass != nclass)
- continue;
-
arg->node_type = ntype;
ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
@@ -502,7 +523,8 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
if (items)
MEM_freeN(items);
}
- NODE_TYPES_END
+
+ BLI_array_free(sorted_ntypes);
}
static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 222fe27983c..2627b978b40 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -59,6 +59,7 @@
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_keyframing.h"
+#include "ED_armature.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -743,14 +744,35 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
TreeElement *te;
int xdelta, ytop;
-
- // TODO: make this get this info from context instead...
- if (OBACT == NULL)
+
+ Object *obact = OBACT;
+
+ if (!obact)
return OPERATOR_CANCELLED;
-
- te = outliner_find_id(so, &so->tree, (ID *)OBACT);
+
+
+ te = outliner_find_id(so, &so->tree, &obact->id);
+
+ if (obact->type == OB_ARMATURE) {
+ /* traverse down the bone hierarchy in case of armature */
+ TreeElement *te_obact = te;
+
+ if (obact->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ if (pchan) {
+ te = outliner_find_posechannel(so, &te_obact->subtree, pchan);
+ }
+ }
+ else if (obact->mode & OB_MODE_EDIT) {
+ EditBone *ebone = CTX_data_active_bone(C);
+ if (ebone) {
+ te = outliner_find_editbone(so, &te_obact->subtree, ebone);
+ }
+ }
+ }
+
if (te) {
- /* open up tree to active object */
+ /* open up tree to active object/bone */
if (outliner_open_back(te)) {
outliner_set_coordinates(ar, so);
}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 5db4897b36d..dc81be7a8e0 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -42,6 +42,8 @@ struct bContext;
struct Scene;
struct ID;
struct Object;
+struct bPoseChannel;
+struct EditBone;
typedef struct TreeElement {
struct TreeElement *next, *prev, *parent;
@@ -128,9 +130,11 @@ typedef enum {
void outliner_free_tree(ListBase *lb);
void outliner_cleanup_tree(struct SpaceOops *soops);
-TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse);
-TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem);
-TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id);
+TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse);
+TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
+TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id);
+TreeElement *outliner_find_posechannel(struct SpaceOops *soops, ListBase *lb, const struct bPoseChannel *pchan);
+TreeElement *outliner_find_editbone(struct SpaceOops *soops, ListBase *lb, const struct EditBone *ebone);
struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SpaceOops *soops);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 84f8c629c5d..21bee2c7cce 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -612,6 +612,8 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature
static eOLDrawState tree_element_active_ebone(
bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive)
{
+ BLI_assert(scene->obedit != NULL);
+
bArmature *arm = scene->obedit->data;
EditBone *ebone = te->directdata;
eOLDrawState status = OL_DRAWSEL_NONE;
@@ -915,11 +917,14 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
/* name and first icon */
else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
- /* always makes active object */
- if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
+ /* always makes active object, except for some specific types.
+ * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want
+ * to switch out of edit mode (see T48328 for details). */
+ if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) {
tree_element_set_active_object(C, scene, soops, te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
recursive && tselem->type == 0);
+ }
if (tselem->type == 0) { // the lib blocks
/* editmode? */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index d688e628967..a687f61d69f 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -199,7 +199,7 @@ void outliner_cleanup_tree(SpaceOops *soops)
}
/* Find specific item from the treestore */
-TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
+TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
{
TreeElement *te, *tes;
for (te = lb->first; te; te = te->next) {
@@ -211,7 +211,7 @@ TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
}
/* tse is not in the treestore, we use its contents to find a match */
-TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
+TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
@@ -226,25 +226,63 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
}
/* Find treestore that refers to given ID */
-TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
+TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
{
- TreeElement *te, *tes;
- TreeStoreElem *tselem;
-
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0) {
- if (tselem->id == id) return te;
+ if (tselem->id == id) {
+ return te;
+ }
/* only deeper on scene or object */
- if (te->idcode == ID_OB || te->idcode == ID_SCE || (soops->outlinevis == SO_GROUPS && te->idcode == ID_GR)) {
- tes = outliner_find_id(soops, &te->subtree, id);
- if (tes) return tes;
+ if (ELEM(te->idcode, ID_OB, ID_SCE) ||
+ ((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR)))
+ {
+ TreeElement *tes = outliner_find_id(soops, &te->subtree, id);
+ if (tes) {
+ return tes;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+TreeElement *outliner_find_posechannel(SpaceOops *soops, ListBase *lb, const bPoseChannel *pchan)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if (te->directdata == pchan) {
+ return te;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
+ TreeElement *tes = outliner_find_posechannel(soops, &te->subtree, pchan);
+ if (tes) {
+ return tes;
}
}
}
return NULL;
}
+TreeElement *outliner_find_editbone(SpaceOops *soops, ListBase *lb, const EditBone *ebone)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if (te->directdata == ebone) {
+ return te;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (ELEM(tselem->type, 0, TSE_EBONE)) {
+ TreeElement *tes = outliner_find_editbone(soops, &te->subtree, ebone);
+ if (tes) {
+ return tes;
+ }
+ }
+ }
+ return NULL;
+}
ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
{
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index df3e508ae0e..8ae89941bdb 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -61,6 +61,7 @@
/* for menu/popup icons etc etc*/
+#include "ED_anim_api.h"
#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_transform.h"
@@ -1505,23 +1506,20 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
{
-#define HEADER_LENGTH 40
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
if (sa) {
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str);
+ BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %s"), num_str);
}
else {
- BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+ BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %d"), offset);
}
}
ED_area_headerprint(sa, msg);
-
-#undef HEADER_LENGTH
}
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -2697,6 +2695,29 @@ void SEQUENCER_OT_view_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
+static int sequencer_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "SEQUENCER_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = sequencer_view_frame_exec;
+ ot->poll = ED_operator_sequencer_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* view_all operator */
static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 3e228fd0b31..730cc117287 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -121,6 +121,7 @@ void SEQUENCER_OT_rendersize(struct wmOperatorType *ot);
void SEQUENCER_OT_view_toggle(struct wmOperatorType *ot);
void SEQUENCER_OT_view_all(struct wmOperatorType *ot);
void SEQUENCER_OT_view_selected(struct wmOperatorType *ot);
+void SEQUENCER_OT_view_frame(struct wmOperatorType *ot);
void SEQUENCER_OT_view_zoom_ratio(struct wmOperatorType *ot);
void SEQUENCER_OT_view_ghost_border(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 3d08e0c5ed8..655e029cfdd 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -84,6 +84,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_view_all);
WM_operatortype_append(SEQUENCER_OT_view_selected);
+ WM_operatortype_append(SEQUENCER_OT_view_frame);
WM_operatortype_append(SEQUENCER_OT_view_all_preview);
WM_operatortype_append(SEQUENCER_OT_view_toggle);
WM_operatortype_append(SEQUENCER_OT_view_zoom_ratio);
@@ -202,6 +203,7 @@ void sequencer_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SEQUENCER_OT_view_frame", PAD0, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEUPKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "next", true);
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 87270bace9a..0a6a9a81e63 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -79,7 +79,15 @@ static SpaceLink *text_new(const bContext *UNUSED(C))
BLI_addtail(&stext->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
-
+
+ /* properties region */
+ ar = MEM_callocN(sizeof(ARegion), "properties region for text");
+
+ BLI_addtail(&stext->regionbase, ar);
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = RGN_FLAG_HIDDEN;
+
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for text");
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 9448f6af69f..81605a80f69 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1009,7 +1009,7 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
if (lines >= DOC_HEIGHT) break;
}
- if (0 /* XXX doc_scroll*/ > 0 && lines < DOC_HEIGHT) {
+ if (0 /* XXX doc_scroll*/ /* > 0 && lines < DOC_HEIGHT */) {
// XXX doc_scroll--;
draw_documentation(st, ar);
}
diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c
index e2e861fda38..7dd45327352 100644
--- a/source/blender/editors/space_time/time_ops.c
+++ b/source/blender/editors/space_time/time_ops.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
+#include "ED_anim_api.h"
#include "ED_screen.h"
#include "WM_api.h"
@@ -140,18 +141,18 @@ static int time_view_all_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- View2D *v2d = (ar) ? &ar->v2d : NULL;
- float extra;
-
+
if (ELEM(NULL, scene, ar))
return OPERATOR_CANCELLED;
-
+
+ View2D *v2d = &ar->v2d;
+
/* set extents of view to start/end frames (Preview Range too) */
v2d->cur.xmin = (float)PSFRA;
v2d->cur.xmax = (float)PEFRA;
/* we need an extra "buffer" factor on either side so that the endpoints are visible */
- extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
+ const float extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
v2d->cur.xmin -= extra;
v2d->cur.xmax += extra;
@@ -176,6 +177,31 @@ static void TIME_OT_view_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ************************ View Frame Operator *******************************/
+
+static int time_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
+static void TIME_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "TIME_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = time_view_frame_exec;
+ ot->poll = ED_operator_timeline_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************** registration **********************************/
void time_operatortypes(void)
@@ -183,6 +209,7 @@ void time_operatortypes(void)
WM_operatortype_append(TIME_OT_start_frame_set);
WM_operatortype_append(TIME_OT_end_frame_set);
WM_operatortype_append(TIME_OT_view_all);
+ WM_operatortype_append(TIME_OT_view_frame);
}
void time_keymap(wmKeyConfig *keyconf)
@@ -193,5 +220,6 @@ void time_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TIME_OT_view_frame", PAD0, KM_PRESS, 0, 0);
}
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index c6b2ccee85b..f7c1e2ee981 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
+#include "BKE_curve.h"
#include "BIF_gl.h"
@@ -1093,20 +1094,101 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
glPopMatrix();
}
-static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, float length, float zwidth)
+/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
+ *
+ * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
+ * position here anyway), and that we can simply apply the bbone settings to get the desired effect...
+ */
+static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
+ float mat3[3][3];
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ int a;
+
+ length = ebone->length;
+
+ hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
+ hlength2 = ebone->ease2 * length * 0.390464f;
+
+ /* find the handle points, since this is inside bone space, the
+ * first point = (0, 0, 0)
+ * last point = (0, length, 0)
+ *
+ * we also just apply all the "extra effects", since they're the whole reason we're doing this...
+ */
+ h1[0] = ebone->curveInX;
+ h1[1] = hlength1;
+ h1[2] = ebone->curveInY;
+ roll1 = ebone->roll1;
+
+ h2[0] = ebone->curveOutX;
+ h2[1] = -hlength2;
+ h2[2] = ebone->curveOutY;
+ roll2 = ebone->roll2;
+
+ /* make curve */
+ if (ebone->segments > MAX_BBONE_SUBDIV)
+ ebone->segments = MAX_BBONE_SUBDIV;
+
+ BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+
+ equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
+
+ /* make transformation matrices for the segments for drawing */
+ for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
+ sub_v3_v3v3(h1, fp + 4, fp);
+ vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
+
+ copy_m4_m3(result_array[a].mat, mat3);
+ copy_v3_v3(result_array[a].mat[3], fp);
+
+ /* "extra" scale facs... */
+ {
+ const int num_segments = ebone->segments;
+
+ const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+ const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+ }
+}
+
+static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth)
{
int segments = 0;
if (pchan)
segments = pchan->bone->segments;
+ else if (ebone)
+ segments = ebone->segments;
- if ((segments > 1) && (pchan)) {
+ if (segments > 1) {
float dlen = length / (float)segments;
Mat4 bbone[MAX_BBONE_SUBDIV];
int a;
-
- b_bone_spline_setup(pchan, 0, bbone);
-
+
+ if (pchan) {
+ b_bone_spline_setup(pchan, 0, bbone);
+ }
+ else if (ebone) {
+ ebone_spline_preview(ebone, bbone);
+ }
+
for (a = 0; a < segments; a++) {
glPushMatrix();
glMultMatrixf(bbone[a].mat);
@@ -1177,7 +1259,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
else
UI_ThemeColor(TH_BONE_SOLID);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
/* disable solid drawing */
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -1190,7 +1272,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
glDisable(GL_BLEND);
}
@@ -1200,7 +1282,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
}
- draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth);
}
}
@@ -1892,7 +1974,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
/* custom bone may draw outline double-width */
- glLineWidth(1.0f);
+ if (arm->flag & ARM_POSEMODE) {
+ glLineWidth(1.0f);
+ }
/* wire draw over solid only in posemode */
if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 345e47940d5..a73a055c5c8 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -713,6 +713,8 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
}
}
}
+
+ dm->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
}
static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr))
@@ -999,7 +1001,16 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
else {
userData.me = NULL;
- update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+ if ((ob->mode & OB_MODE_ALL_PAINT) == 0) {
+
+ /* Note: this isn't efficient and runs on every redraw,
+ * its needed so material colors are used for vertex colors.
+ * In the future we will likely remove 'texface' so, just avoid running this where possible,
+ * (when vertex paint or weight paint are used). */
+
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+ }
+
dm->drawFacesTex(
dm, draw_tface__set_draw, compareDrawOptions,
&userData, dm_draw_flag);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 6199ed85ba1..65f1f375443 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -3678,29 +3678,10 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
{
RegionView3D *rv3d = ar->regiondata;
Mesh *me = ob->data;
- BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true); /* annoying but active faces is stored differently */
- BMEdge *eed_act = NULL;
- BMVert *eve_act = NULL;
- bool use_occlude_wire = (v3d->flag2 & V3D_OCCLUDE_WIRE) && (dt > OB_WIRE);
+ const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
+ bool use_depth_offset = false;
glLineWidth(1);
-
- if (em->bm->selected.last) {
- BMEditSelection *ese = em->bm->selected.last;
- /* face is handled above */
-#if 0
- if (ese->type == BM_FACE) {
- efa_act = (BMFace *)ese->data;
- }
- else
-#endif
- if (ese->htype == BM_EDGE) {
- eed_act = (BMEdge *)ese->ele;
- }
- else if (ese->htype == BM_VERT) {
- eve_act = (BMVert *)ese->ele;
- }
- }
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
@@ -3710,6 +3691,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0);
+ use_depth_offset = true;
}
else {
glEnable(GL_DEPTH_TEST);
@@ -3756,6 +3738,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0);
+ use_depth_offset = true;
}
else {
if (cageDM != finalDM) {
@@ -3764,145 +3747,172 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
}
- if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */
- unsigned char col1[4], col2[4], col3[4];
+ if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
+ /* pass */
+ }
+ else {
+ /* annoying but active faces is stored differently */
+ BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true);
+ BMEdge *eed_act = NULL;
+ BMVert *eve_act = NULL;
+
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
+ /* face is handled above */
+#if 0
+ if (ese->type == BM_FACE) {
+ efa_act = (BMFace *)ese->data;
+ }
+ else
+#endif
+ if (ese->htype == BM_EDGE) {
+ eed_act = (BMEdge *)ese->ele;
+ }
+ else if (ese->htype == BM_VERT) {
+ eve_act = (BMVert *)ese->ele;
+ }
+ }
+
+ if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */
+ unsigned char col1[4], col2[4], col3[4];
#ifdef WITH_FREESTYLE
- unsigned char col4[4];
+ unsigned char col4[4];
#endif
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
+ UI_GetThemeColor4ubv(TH_FACE, col1);
+ UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
+ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
#ifdef WITH_FREESTYLE
- UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
+ UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
#endif
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
- /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
- if (check_object_draw_texture(scene, v3d, dt))
- col1[3] = 0;
+ /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
+ if (check_object_draw_texture(scene, v3d, dt))
+ col1[3] = 0;
#ifdef WITH_FREESTYLE
- if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE))
- col4[3] = 0;
+ if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE))
+ col4[3] = 0;
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
#endif
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
- else if (efa_act) {
- /* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active */
- unsigned char col1[4], col2[4], col3[4];
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ else if (efa_act) {
+ /* even if draw faces is off it would be nice to draw the stipple face
+ * Make all other faces zero alpha except for the active */
+ unsigned char col1[4], col2[4], col3[4];
#ifdef WITH_FREESTYLE
- unsigned char col4[4];
- col4[3] = 0; /* don't draw */
+ unsigned char col4[4];
+ col4[3] = 0; /* don't draw */
#endif
- col1[3] = col2[3] = 0; /* don't draw */
+ col1[3] = col2[3] = 0; /* don't draw */
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
+ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
#ifdef WITH_FREESTYLE
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
#endif
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
- /* here starts all fancy draw-extra over */
- if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
- /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
-
- /* only draw selected edges otherwise there is no way of telling if a face is selected */
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
-
- }
- else {
- if (me->drawflag & ME_DRAWSEAMS) {
- UI_ThemeColor(TH_EDGE_SEAM);
- glLineWidth(2);
+ /* here starts all fancy draw-extra over */
+ if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
+ /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
- draw_dm_edges_seams(em, cageDM);
+ /* only draw selected edges otherwise there is no way of telling if a face is selected */
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
- glColor3ub(0, 0, 0);
}
-
- if (me->drawflag & ME_DRAWSHARP) {
- UI_ThemeColor(TH_EDGE_SHARP);
- glLineWidth(2);
+ else {
+ if (me->drawflag & ME_DRAWSEAMS) {
+ UI_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
- draw_dm_edges_sharp(em, cageDM);
+ draw_dm_edges_seams(em, cageDM);
- glColor3ub(0, 0, 0);
- }
+ glColor3ub(0, 0, 0);
+ }
+
+ if (me->drawflag & ME_DRAWSHARP) {
+ UI_ThemeColor(TH_EDGE_SHARP);
+ glLineWidth(2);
+
+ draw_dm_edges_sharp(em, cageDM);
+
+ glColor3ub(0, 0, 0);
+ }
#ifdef WITH_FREESTYLE
- if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
- UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
- glLineWidth(2);
-
- draw_dm_edges_freestyle(em, cageDM);
-
- glColor3ub(0, 0, 0);
- }
-#endif
-
- if (me->drawflag & ME_DRAWCREASES) {
- draw_dm_creases(em, cageDM);
- }
- if (me->drawflag & ME_DRAWBWEIGHTS) {
- draw_dm_bweights(em, scene, cageDM);
- }
+ if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
+ UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
+ glLineWidth(2);
- glLineWidth(1);
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
- }
+ draw_dm_edges_freestyle(em, cageDM);
- {
- draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
+ glColor3ub(0, 0, 0);
+ }
+#endif
- if (me->drawflag & ME_DRAWNORMALS) {
- UI_ThemeColor(TH_NORMAL);
- draw_dm_face_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_VNORMALS) {
- UI_ThemeColor(TH_VNORMAL);
- draw_dm_vert_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_LNORMALS) {
- UI_ThemeColor(TH_LNORMAL);
- draw_dm_loop_normals(em, scene, ob, cageDM);
- }
+ if (me->drawflag & ME_DRAWCREASES) {
+ draw_dm_creases(em, cageDM);
+ }
+ if (me->drawflag & ME_DRAWBWEIGHTS) {
+ draw_dm_bweights(em, scene, cageDM);
+ }
- if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
- ME_DRAWEXTRA_FACEAREA |
- ME_DRAWEXTRA_FACEANG |
- ME_DRAWEXTRA_EDGEANG)) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
- {
- draw_em_measure_stats(ar, v3d, ob, em, &scene->unit);
+ glLineWidth(1);
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
}
- if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
{
- draw_em_indices(em);
+ draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
+
+ if (me->drawflag & ME_DRAWNORMALS) {
+ UI_ThemeColor(TH_NORMAL);
+ draw_dm_face_normals(em, scene, ob, cageDM);
+ }
+ if (me->drawflag & ME_DRAW_VNORMALS) {
+ UI_ThemeColor(TH_VNORMAL);
+ draw_dm_vert_normals(em, scene, ob, cageDM);
+ }
+ if (me->drawflag & ME_DRAW_LNORMALS) {
+ UI_ThemeColor(TH_LNORMAL);
+ draw_dm_loop_normals(em, scene, ob, cageDM);
+ }
+
+ if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
+ ME_DRAWEXTRA_FACEAREA |
+ ME_DRAWEXTRA_FACEANG |
+ ME_DRAWEXTRA_EDGEANG)) &&
+ !(v3d->flag2 & V3D_RENDER_OVERRIDE))
+ {
+ draw_em_measure_stats(ar, v3d, ob, em, &scene->unit);
+ }
+
+ if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
+ !(v3d->flag2 & V3D_RENDER_OVERRIDE))
+ {
+ draw_em_indices(em);
+ }
}
}
- if (dt > OB_WIRE) {
+ if (use_depth_offset) {
glDepthMask(1);
ED_view3d_polygon_offset(rv3d, 0.0);
GPU_object_material_unbind();
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 7f1a7a059fc..184b9ff5b15 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -315,12 +315,12 @@ static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **
if (unit->system) {
/* Use GRID_MIN_PX * 2 for units because very very small grid
* items are less useful when dealing with units */
- void *usys;
+ const void *usys;
int len, i;
double dx_scalar;
float blend_fac;
- bUnit_GetSystem(&usys, &len, unit->system, B_UNIT_LENGTH);
+ bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
if (usys) {
i = len;
@@ -455,10 +455,10 @@ float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
{
/* apply units */
if (scene->unit.system) {
- void *usys;
+ const void *usys;
int len;
- bUnit_GetSystem(&usys, &len, scene->unit.system, B_UNIT_LENGTH);
+ bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
if (usys) {
int i = bUnit_GetBaseUnit(usys);
@@ -3976,6 +3976,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
drawviewborder(scene, ar, v3d);
}
else if (v3d->flag2 & V3D_RENDER_BORDER) {
+ glLineWidth(1.0f);
setlinestyle(3);
cpack(0x4040FF);
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 7cd20401a53..c7a10d65071 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -37,6 +37,7 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
#include "MEM_guardedalloc.h"
@@ -74,6 +75,7 @@
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_mesh.h"
+#include "ED_gpencil.h"
#include "ED_view3d.h"
#include "UI_resources.h"
@@ -1229,6 +1231,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
/* switch from camera view when: */
if (view3d_ensure_persp(vod->v3d, vod->ar)) {
/* If we're switching from camera view to the perspective one,
@@ -1647,8 +1651,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewops_data_alloc(C, op);
viewops_data_create_ex(C, op, event,
(U.uiflag & USER_ORBIT_SELECTION) != 0, false);
-
vod = op->customdata;
+
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
v3d = vod->v3d;
rv3d = vod->rv3d;
@@ -1715,6 +1721,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
(U.uiflag & USER_ORBIT_SELECTION) != 0, false);
vod = op->customdata;
+
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
v3d = vod->v3d;
rv3d = vod->rv3d;
@@ -2024,6 +2033,8 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewops_data_create(C, op, event);
vod = op->customdata;
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
if (event->type == MOUSEPAN) {
/* invert it, trackpad scroll follows same principle as 2d windows this way */
viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
@@ -2503,6 +2514,8 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewops_data_create(C, op, event);
vod = op->customdata;
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
/* if one or the other zoom position aren't set, set from event */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
RNA_int_set(op->ptr, "mx", event->x);
@@ -2743,6 +2756,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
/* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */
/* switch from camera view when: */
if (vod->rv3d->persp != RV3D_PERSP) {
@@ -2838,6 +2853,8 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
float afm[3];
float size;
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
/* SMOOTHVIEW */
float new_ofs[3];
float new_dist;
@@ -3004,6 +3021,8 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
Object *ob = OBACT;
Object *obedit = CTX_data_edit_object(C);
float min[3], max[3];
@@ -3016,6 +3035,10 @@ static int viewselected_exec(bContext *C, wmOperator *op)
INIT_MINMAX(min, max);
+ if (is_gp_edit) {
+ ob = NULL;
+ }
+
if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) {
/* hard-coded exception, we look for the one selected armature */
/* this is weak code this way, we should make a generic active/selection callback interface once... */
@@ -3032,7 +3055,19 @@ static int viewselected_exec(bContext *C, wmOperator *op)
}
- if (obedit) {
+ if (is_gp_edit) {
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* we're only interested in selected points here... */
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
+ if (ED_gpencil_stroke_minmax(gps, true, min, max)) {
+ ok = true;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else if (obedit) {
ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
@@ -3196,6 +3231,8 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
/* non camera center */
float new_ofs[3];
negate_v3_v3(new_ofs, ED_view3d_cursor3d_get(scene, v3d));
@@ -3235,6 +3272,8 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
float new_ofs[3];
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
view3d_operator_needs_opengl(C);
if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false, NULL)) {
@@ -3840,6 +3879,8 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
ED_view3d_context_user_region(C, &v3d, &ar);
rv3d = ar->regiondata;
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
viewnum = RNA_enum_get(op->ptr, "type");
align_active = RNA_boolean_get(op->ptr, "align_active");
@@ -3990,6 +4031,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
rv3d = ar->regiondata;
}
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
if ((rv3d->viewlock & RV3D_LOCKED) == 0 || (view_opposite != RV3D_VIEW_USER)) {
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
@@ -4195,6 +4238,9 @@ static int viewroll_exec(bContext *C, wmOperator *op)
rv3d = ar->regiondata;
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
+
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
int type = RNA_enum_get(op->ptr, "type");
float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle);
float mousevec[3];
@@ -4247,6 +4293,8 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewops_data_create(C, op, event);
vod = op->customdata;
+ ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
+
/* overwrite the mouse vector with the view direction */
normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]);
negate_v3(vod->mousevec);
@@ -5171,85 +5219,3 @@ void ED_view3D_lock_clear(View3D *v3d)
v3d->ob_centre_cursor = false;
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
-
-/**
- * Convenience function for snap ray-casting.
- *
- * Given a ray, cast it into the scene (snapping to faces).
- *
- * \return Snap success
- */
-bool ED_view3d_snap_from_ray(
- Scene *scene,
- const float ray_start[3], const float ray_normal[3],
- float r_co[3])
-{
- float r_no_dummy[3];
- float ray_dist = BVH_RAYCAST_DIST_MAX;
- bool ret;
-
- struct Object *obedit = scene->obedit;
-
- /* try snap edge, then face if it fails */
- ret = snapObjectsRayEx(
- scene, NULL, NULL, NULL, obedit,
- NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
- ray_start, ray_normal, &ray_dist,
- r_co, r_no_dummy, NULL, NULL,
- NULL, NULL);
-
- return ret;
-}
-
-/**
- * Convenience function for performing snapping.
- *
- * Given a 2D region value, snap to vert/edge/face.
- *
- * \param mval: 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 use_obedit: Use editmode cage.
- * \param use_vert: Snap to verts.
- * \param use_edge: Snap to edges.
- * \param use_face: Snap to faces.
- * \param r_co: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success
- */
-bool ED_view3d_snap_from_region(
- Scene *scene, View3D *v3d, ARegion *ar,
- const float mval[2], float dist_px,
- bool use_depth, bool use_obedit,
- bool use_vert, bool use_edge, bool use_face,
- float r_co[3], float r_no[3])
-{
- float r_no_dummy[3];
- float ray_dist = BVH_RAYCAST_DIST_MAX;
- bool is_hit = false;
- float *r_no_ptr = r_no ? r_no : r_no_dummy;
-
- struct Object *obedit = use_obedit ? scene->obedit : NULL;
- const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
- const bool elem_test[3] = {use_vert, use_edge, use_face};
-
- BLI_assert(use_vert || use_edge || use_face);
-
- for (int i = 0; i < 3; i++) {
- if (elem_test[i] && (is_hit == false || use_depth)) {
- if (use_depth == false) {
- ray_dist = BVH_RAYCAST_DIST_MAX;
- }
- if (snapObjectsEx(
- scene, v3d, ar, NULL, obedit,
- mval, SNAP_ALL, elem_type[i],
- &ray_dist,
- r_co, r_no_ptr, &dist_px))
- {
- is_hit = true;
- }
- }
- }
-
- return is_hit;
-}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index c398356e941..901c5c8d4c2 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -229,6 +229,10 @@ void ED_view3d_smooth_view(
struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx,
const V3D_SmoothParams *sview);
+void ED_view3d_smooth_view_force_finish(
+ struct bContext *C,
+ struct View3D *v3d, struct ARegion *ar);
+
void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index a5411da131b..c30e688f1e7 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -44,7 +44,7 @@
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
-#include "BKE_blender.h"
+#include "BKE_blender_copybuffer.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index c364148c9f1..797d97586c7 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -217,8 +217,8 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4
float tvec[2];
eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
if (ret == V3D_PROJ_RET_OK) {
- if (finite(tvec[0]) &&
- finite(tvec[1]))
+ if (isfinite(tvec[0]) &&
+ isfinite(tvec[1]))
{
copy_v2_v2(r_co, tvec);
}
@@ -481,19 +481,22 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
{
RegionView3D *rv3d = ar->regiondata;
- float line_sta[3];
- float line_end[3];
+ float ray_origin[3];
+ float ray_direction[3];
+ float lambda;
if (rv3d->is_persp) {
- float mousevec[3], lambda;
- copy_v3_v3(line_sta, rv3d->viewinv[3]);
- ED_view3d_win_to_vector(ar, mval, mousevec);
- add_v3_v3v3(line_end, line_sta, mousevec);
+ float plane[4];
+
+ copy_v3_v3(ray_origin, rv3d->viewinv[3]);
+ ED_view3d_win_to_vector(ar, mval, ray_direction);
/* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the
* view no matter what, so apply the unsigned factor instead */
- lambda = line_plane_factor_v3(depth_pt, rv3d->viewinv[2], line_sta, line_end);
- interp_v3_v3v3(out, line_sta, line_end, fabsf(lambda));
+ plane_from_point_normal_v3(plane, depth_pt, rv3d->viewinv[2]);
+
+ isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, false);
+ lambda = fabsf(lambda);
}
else {
float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
@@ -504,13 +507,15 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
dx += rv3d->camdx * zoomfac;
dy += rv3d->camdy * zoomfac;
}
- line_sta[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
- line_sta[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
- line_sta[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
+ ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
+ ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
+ ray_origin[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
- add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
- closest_to_line_v3(out, depth_pt, line_sta, line_end);
+ copy_v3_v3(ray_direction, rv3d->viewinv[2]);
+ lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction);
}
+
+ madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda);
}
void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3])
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 198cc3e5703..dfa76753f64 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_unit.h"
#include "BKE_gpencil.h"
@@ -46,6 +48,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_space_api.h"
#include "BLF_api.h"
@@ -109,6 +113,8 @@ typedef struct RulerInfo {
int state;
float drag_start_co[3];
+ struct SnapObjectContext *snap_context;
+
/* wm state */
wmWindow *win;
ScrArea *sa;
@@ -128,6 +134,7 @@ static RulerItem *ruler_item_add(RulerInfo *ruler_info)
static void ruler_item_remove(RulerInfo *ruler_info, RulerItem *ruler_item)
{
BLI_remlink(&ruler_info->items, ruler_item);
+
MEM_freeN(ruler_item);
}
@@ -632,6 +639,9 @@ static void view3d_ruler_end(const struct bContext *UNUSED(C), RulerInfo *ruler_
static void view3d_ruler_free(RulerInfo *ruler_info)
{
BLI_freelistN(&ruler_info->items);
+
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+
MEM_freeN(ruler_info);
}
@@ -642,11 +652,12 @@ static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3],
}
/* use for mousemove events */
-static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, const int mval[2],
- const bool do_thickness, const bool do_snap)
+static bool view3d_ruler_item_mousemove(
+ RulerInfo *ruler_info, const int mval[2],
+ const bool do_thickness, const bool do_snap)
{
const float eps_bias = 0.0002f;
- const float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
+ float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
RulerItem *ruler_item = ruler_item_active_get(ruler_info);
ruler_info->snap_flag &= ~RULER_SNAP_OK;
@@ -657,8 +668,8 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
copy_v3_v3(co, ruler_info->drag_start_co);
view3d_ruler_item_project(ruler_info, co, mval);
if (do_thickness && ruler_item->co_index != 1) {
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = ruler_info->sa->spacedata.first;
+ // Scene *scene = CTX_data_scene(C);
+ // View3D *v3d = ruler_info->sa->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -666,33 +677,37 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
co_other = ruler_item->co[ruler_item->co_index == 0 ? 2 : 0];
- if (ED_view3d_snap_from_region(
- scene, v3d, ruler_info->ar,
- mval_fl, dist_px,
- true, false,
- false, false, true,
+ if (ED_transform_snap_object_project_view3d_mixed(
+ ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .snap_to_flag = SCE_SELECT_FACE,
+ },
+ mval_fl, &dist_px, true,
co, ray_normal))
{
negate_v3(ray_normal);
/* add some bias */
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
- ED_view3d_snap_from_ray(
- scene,
- ray_start, ray_normal,
- co_other);
+ ED_transform_snap_object_project_ray(
+ ruler_info->snap_context,
+ ray_start, ray_normal, NULL,
+ co_other, NULL);
}
}
else if (do_snap) {
- Scene *scene = CTX_data_scene(C);
+ // Scene *scene = CTX_data_scene(C);
View3D *v3d = ruler_info->sa->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
bool use_depth = (v3d->drawtype >= OB_SOLID);
- if (ED_view3d_snap_from_region(
- scene, v3d, ruler_info->ar,
- mval_fl, dist_px,
- use_depth, false,
- true, true, use_depth,
+ if (ED_transform_snap_object_project_view3d_mixed(
+ ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .snap_to_flag = (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
+ },
+ mval_fl, &dist_px, use_depth,
co, NULL))
{
ruler_info->snap_flag |= RULER_SNAP_OK;
@@ -707,13 +722,13 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
static void view3d_ruler_header_update(ScrArea *sa)
{
- const char *text = "Ctrl+LMB: Add, "
- "Del: Remove, "
- "Ctrl+Drag: Snap, "
- "Shift+Drag: Thickness, "
- "Ctrl+C: Copy Value, "
- "Enter: Store, "
- "Esc: Cancel";
+ const char *text = IFACE_("Ctrl+LMB: Add, "
+ "Del: Remove, "
+ "Ctrl+Drag: Snap, "
+ "Shift+Drag: Thickness, "
+ "Ctrl+C: Copy Value, "
+ "Enter: Store, "
+ "Esc: Cancel");
ED_area_headerprint(sa, text);
}
@@ -736,6 +751,10 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
+ ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ ar, CTX_wm_view3d(C));
+
ruler_info->win = win;
ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
@@ -818,7 +837,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (use_depth) {
/* snap the first point added, not essential but handy */
ruler_item->co_index = 0;
- view3d_ruler_item_mousemove(C, ruler_info, event->mval, false, true);
+ view3d_ruler_item_mousemove(ruler_info, event->mval, false, true);
copy_v3_v3(ruler_info->drag_start_co, ruler_item->co[ruler_item->co_index]);
}
else {
@@ -871,7 +890,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* update the new location */
- view3d_ruler_item_mousemove(C, ruler_info, event->mval,
+ view3d_ruler_item_mousemove(ruler_info, event->mval,
event->shift != 0, event->ctrl != 0);
do_draw = true;
}
@@ -920,7 +939,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
{
if (ruler_info->state == RULER_STATE_DRAG) {
- if (view3d_ruler_item_mousemove(C, ruler_info, event->mval,
+ if (view3d_ruler_item_mousemove(ruler_info, event->mval,
event->shift != 0, event->ctrl != 0))
{
do_draw = true;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 18cb9fb728d..bedcf413bfa 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -418,11 +418,12 @@ static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], cons
for (base = vc->scene->base.first; base; base = base->next) {
if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */
- ED_view3d_project_base(vc->ar, base);
- if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) {
-
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
- base->object->flag = base->flag;
+ if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) {
+ if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) {
+
+ ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
+ base->object->flag = base->flag;
+ }
}
if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) {
do_lasso_select_pose(vc, base->object, mcords, moves, select);
@@ -1096,20 +1097,22 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int
/* two selection methods, the CTRL select uses max dist of 15 */
if (buffer) {
- int a;
- for (a = 0; a < hits; a++) {
+ for (int a = 0; a < hits; a++) {
/* index was converted */
- if (base->selcol == buffer[(4 * a) + 3])
+ if (base->selcol == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
ok = true;
+ break;
+ }
}
}
else {
- int temp, dist = 15;
- ED_view3d_project_base(vc->ar, base);
-
- temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]);
- if (temp < dist)
- ok = true;
+ const int dist = 15 * U.pixelsize;
+ if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) {
+ const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]};
+ if (len_manhattan_v2_int(delta_px) < dist) {
+ ok = true;
+ }
+ }
}
if (ok) {
@@ -1468,7 +1471,7 @@ static bool ed_object_select_pick(
const bool has_bones = selectbuffer_has_bones(buffer, hits);
/* note; shift+alt goes to group-flush-selecting */
- if (has_bones == 0 && enumerate) {
+ if (enumerate) {
basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle);
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 305b4a3785e..c35646b9e92 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -337,17 +337,12 @@ void ED_view3d_smooth_view(
}
/* only meant for timer usage */
-static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool sync_boxview)
{
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
struct SmoothView3DStore *sms = rv3d->sms;
float step, step_inv;
- /* escape if not our timer */
- if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata)
- return OPERATOR_PASS_THROUGH;
-
if (sms->time_allowed != 0.0)
step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
else
@@ -404,8 +399,9 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
}
- if (rv3d->viewlock & RV3D_BOXVIEW)
- view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
+ if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) {
+ view3d_boxview_copy(CTX_wm_area(C), ar);
+ }
/* note: this doesn't work right because the v3d->lens is now used in ortho mode r51636,
* when switching camera in quad-view the other ortho views would zoom & reset.
@@ -416,12 +412,47 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
}
else {
- ED_region_tag_redraw(CTX_wm_region(C));
+ ED_region_tag_redraw(ar);
}
-
+}
+
+static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* escape if not our timer */
+ if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ view3d_smoothview_apply(C, v3d, ar, true);
+
return OPERATOR_FINISHED;
}
+/**
+ * Apply the smoothview immediately, use when we need to start a new view operation.
+ * (so we don't end up half-applying a view operation when pressing keys quickly).
+ */
+void ED_view3d_smooth_view_force_finish(
+ bContext *C,
+ View3D *v3d, ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d && rv3d->sms) {
+ rv3d->sms->time_allowed = 0.0; /* force finishing */
+ view3d_smoothview_apply(C, v3d, ar, false);
+
+ /* force update of view matrix so tools that run immediately after
+ * can use them without redrawing first */
+ Scene *scene = CTX_data_scene(C);
+ ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL);
+ }
+}
+
void VIEW3D_OT_smoothview(wmOperatorType *ot)
{
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 7e1202aef77..47f81678699 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -49,7 +49,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
-#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "PIL_time.h" /* smoothview */
@@ -306,6 +306,8 @@ typedef struct WalkInfo {
float jump_height; /* maximum jump height */
float speed_factor; /* to use for fast/slow speeds */
+ struct SnapObjectContext *snap_context;
+
struct View3DCameraControl *v3d_camera_control;
} WalkInfo;
@@ -402,12 +404,14 @@ static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk
/**
* \param r_distance Distance to the hit point
*/
-static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance)
+static bool walk_floor_distance_get(
+ RegionView3D *rv3d, WalkInfo *walk, const float dvec[3],
+ float *r_distance)
{
float ray_normal[3] = {0, 0, -1}; /* down */
float ray_start[3];
float r_location[3];
- float r_normal[3];
+ float r_normal_dummy[3];
float dvec_tmp[3];
bool ret;
@@ -418,12 +422,10 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
- ret = snapObjectsRayEx(
- CTX_data_scene(C), NULL, NULL, NULL, NULL,
- NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ ret = ED_transform_snap_object_project_ray(
+ walk->snap_context,
ray_start, ray_normal, r_distance,
- r_location, r_normal, NULL, NULL,
- NULL, NULL);
+ r_location, r_normal_dummy);
/* artifically scale the distance to the scene size */
*r_distance /= walk->grid;
@@ -435,34 +437,30 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w
* \param r_location Location of the hit point
* \param r_normal Normal of the hit surface, transformed to always face the camera
*/
-static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance)
+static bool walk_ray_cast(
+ RegionView3D *rv3d, WalkInfo *walk,
+ float r_location[3], float r_normal[3], float *ray_distance)
{
- float ray_normal[3] = {0, 0, 1}; /* forward */
+ float ray_normal[3] = {0, 0, -1}; /* forward */
float ray_start[3];
- float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
bool ret;
*ray_distance = BVH_RAYCAST_DIST_MAX;
copy_v3_v3(ray_start, rv3d->viewinv[3]);
- copy_m3_m4(mat, rv3d->viewinv);
- mul_m3_v3(mat, ray_normal);
+ mul_mat3_m4_v3(rv3d->viewinv, ray_normal);
- mul_v3_fl(ray_normal, -1);
normalize_v3(ray_normal);
- ret = snapObjectsRayEx(
- CTX_data_scene(C), NULL, NULL, NULL, NULL,
- NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
- ray_start, ray_normal, ray_distance,
- r_location, r_normal, NULL, NULL,
- NULL, NULL);
-
+ ret = ED_transform_snap_object_project_ray(
+ walk->snap_context,
+ ray_start, ray_normal, NULL,
+ r_location, r_normal);
/* dot is positive if both rays are facing the same direction */
if (dot_v3v3(ray_normal, r_normal) > 0) {
- copy_v3_fl3(r_normal, -r_normal[0], -r_normal[1], -r_normal[2]);
+ negate_v3(r_normal);
}
/* artifically scale the distance to the scene size */
@@ -575,6 +573,9 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
+ walk->snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), walk->scene, SNAP_OBJECT_USE_CACHE,
+ walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->scene, walk->v3d, walk->rv3d,
@@ -625,6 +626,8 @@ static int walkEnd(bContext *C, WalkInfo *walk)
ED_region_draw_cb_exit(walk->ar->type, walk->draw_handle_pixel);
+ ED_transform_snap_object_context_destroy(walk->snap_context);
+
ED_view3d_cameracontrol_release(walk->v3d_camera_control, walk->state == WALK_CANCEL);
rv3d->rflag &= ~RV3D_NAVIGATING;
@@ -897,7 +900,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
{
float loc[3], nor[3];
float distance;
- bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance);
+ bool ret = walk_ray_cast(walk->rv3d, walk, loc, nor, &distance);
/* in case we are teleporting middle way from a jump */
walk->speed_jump = 0.0f;
@@ -1178,7 +1181,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
float difference = -100.0f;
float fall_distance;
- ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);
+ ret = walk_floor_distance_get(rv3d, walk, dvec, &ray_distance);
if (ret) {
difference = walk->view_height - ray_distance;
@@ -1231,7 +1234,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
if (t > walk->teleport.duration) {
/* check to see if we are landing */
- ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);
+ ret = walk_floor_distance_get(rv3d, walk, dvec, &ray_distance);
if (ret) {
difference = walk->view_height - ray_distance;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index f3047c088a9..b7de49d8158 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
transform_ops.c
transform_orientations.c
transform_snap.c
+ transform_snap_object.c
transform.h
)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 29c152c2f6e..5c0c0bcd6c1 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -80,6 +80,7 @@
#include "WM_api.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -93,8 +94,6 @@
/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
// #define USE_NUM_NO_ZERO
-#define MAX_INFO_LEN 256
-
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
static void doEdgeSlide(TransInfo *t, float perc);
static void doVertSlide(TransInfo *t, float perc);
@@ -2910,7 +2909,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float pivot[3];
float warp_end_radius[3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const struct BendCustomData *data = t->custom.mode.data;
const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
@@ -2948,13 +2947,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
&c[0], &c[NUM_STR_REP_LEN],
WM_bool_as_string(is_clamp));
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
RAD2DEGF(values.angle), values.scale * data->warp_init_dist,
WM_bool_as_string(is_clamp));
}
@@ -3104,7 +3103,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
float value;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
copy_m3_m4(persmat, t->viewmat);
@@ -3124,11 +3123,11 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
unit_m3(smat);
@@ -3228,7 +3227,7 @@ static void initResize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -3244,32 +3243,32 @@ static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s%s %s"),
&tvec[0], t->con.text, t->proptext);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
&tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
break;
}
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -3394,7 +3393,7 @@ static void applyResize(TransInfo *t, const int mval[2])
TransData *td;
float mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
if (t->flag & T_AUTOVALUES) {
copy_v3_v3(t->values, t->auto_values);
@@ -3512,7 +3511,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
copy_v3_fl(size, t->values[0]);
@@ -3610,7 +3609,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
float vec[3];
float ratio, radius;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
ratio = t->values[0];
@@ -3629,11 +3628,11 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
@@ -3964,7 +3963,7 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3])
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
@@ -3995,15 +3994,15 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"),
RAD2DEGF(final), t->con.text, t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
applyRotationValue(t, final, t->axis);
@@ -4074,7 +4073,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float axis1[3], axis2[3];
#if 0 /* UNUSED */
@@ -4100,16 +4099,16 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %s %s %s"),
&c[0], &c[NUM_STR_REP_LEN], t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %.2f %.2f %s"),
RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
#if 0 /* UNUSED */
@@ -4206,7 +4205,7 @@ static void initTranslation(TransInfo *t)
}
}
-static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
@@ -4268,15 +4267,15 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s (%s)%s %s %s",
&tvec[0], distvec, t->con.text, t->proptext, autoik);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec,
t->con.text, t->proptext, autoik);
break;
@@ -4284,18 +4283,18 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s (%s)%s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text,
t->proptext, autoik);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
if (t->spacetype == SPACE_NODE) {
@@ -4304,11 +4303,11 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? IFACE_("right") : IFACE_("left");
- char str_km[MAX_INFO_LEN];
+ char str_km[64];
WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km);
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
str_dir, str_km, str_old);
MEM_freeN((void *)str_old);
@@ -4376,7 +4375,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float value_final[3];
if (t->flag & T_AUTOVALUES) {
@@ -4468,7 +4467,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
TransData *td = t->data;
@@ -4481,29 +4480,29 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = -distance;
/* header print for NumInput */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c);
}
else {
/* default header print */
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance);
}
if (t->proptext[0]) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", (");
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, ", (");
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, sizeof(str) - ofs, str + ofs);
}
}
- BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
+ BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" or Alt) Even Thickness %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
@@ -4563,7 +4562,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -4580,13 +4579,13 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
/* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
t->values[0] = final;
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4644,7 +4643,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4659,10 +4658,10 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4724,7 +4723,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
float ratio;
int i;
bool initial_feather = false;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4739,10 +4738,10 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %3f"), ratio);
}
/* detect if no points have feather yet */
@@ -4824,7 +4823,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4839,10 +4838,10 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4897,7 +4896,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
float vec[3], axis[3];
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
distance = t->values[0];
@@ -4914,11 +4913,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
@@ -4989,7 +4988,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float weight;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
weight = t->values[0];
@@ -5008,16 +5007,16 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5069,7 +5068,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float crease;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
crease = t->values[0];
@@ -5088,16 +5087,16 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%.3f %s"), crease, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5151,7 +5150,7 @@ static void initBoneSize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
@@ -5166,13 +5165,13 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_L
/* hmm... perhaps the y-axis values don't need to be shown? */
if (t->con.mode & CON_APPLY) {
if (t->num.idx_max == 0)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s : %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
@@ -5203,7 +5202,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
float size[3], mat[3][3];
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
// TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
/* for manipulator, center handle, the scaling can't be done relative to center */
@@ -5282,7 +5281,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -5297,10 +5296,10 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -6959,7 +6958,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
EdgeSlideData *sld = t->custom.mode.data;
@@ -6982,20 +6981,20 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7527,7 +7526,7 @@ static void doVertSlide(TransInfo *t, float perc)
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
VertSlideData *sld = t->custom.mode.data;
@@ -7550,20 +7549,20 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7607,7 +7606,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -7624,10 +7623,10 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %s"), &c[0]);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final));
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %.2f"), RAD2DEGF(final));
}
/* set roll values */
@@ -7675,7 +7674,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
TransData *td = t->data;
float time;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float fac = 0.1f;
@@ -7704,16 +7703,16 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
outputNumInput(&(t->num), c, &t->scene->unit);
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%.3f %s"), time, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -7759,7 +7758,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/*
* OPTIMIZATION:
@@ -7777,7 +7776,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
t->con.applySize(t, NULL, mat);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text);
+ BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -7906,7 +7905,7 @@ static void initSeqSlide(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
}
-static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN])
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -7918,15 +7917,15 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, UI_MAX_DRAW_STR - ofs, str + ofs);
}
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" or Alt) Expand to fit %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
@@ -7948,7 +7947,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
static void applySeqSlide(TransInfo *t, const int mval[2])
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
snapSequenceBounds(t, mval);
@@ -8127,7 +8126,7 @@ static void initTimeTranslate(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
int ofs = 0;
@@ -8166,10 +8165,10 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("DeltaX: %s"), &tvec[0]);
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -8231,7 +8230,7 @@ static void applyTimeTranslateValue(TransInfo *t)
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate translation amount from mouse movement - in 'time-grid space' */
if (t->flag & T_MODAL) {
@@ -8323,7 +8322,7 @@ static void initTimeSlide(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN])
+static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8343,7 +8342,7 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LE
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("TimeSlide: %s"), &tvec[0]);
}
static void applyTimeSlideValue(TransInfo *t, float sval)
@@ -8400,7 +8399,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
const float *range = t->custom.mode.data;
float minx = range[0];
float maxx = range[1];
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate mouse co-ordinates */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
@@ -8473,7 +8472,7 @@ static void initTimeScale(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8482,7 +8481,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
else
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleX: %s"), &tvec[0]);
}
static void applyTimeScaleValue(TransInfo *t)
@@ -8526,7 +8525,7 @@ static void applyTimeScaleValue(TransInfo *t)
static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -8558,5 +8557,3 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
-
-#undef MAX_INFO_LEN
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index c156e9ecec0..11151a9c65a 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -59,6 +59,7 @@ struct wmTimer;
struct ARegion;
struct ReportList;
struct EditBone;
+struct SnapObjectContext;
/* transinfo->redraw */
typedef enum {
@@ -101,6 +102,11 @@ typedef struct TransSnap {
* where the smallest absolute value defines whats closest.
*/
float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]);
+
+ /**
+ * Re-usable snap context data.
+ */
+ struct SnapObjectContext *object_context;
} TransSnap;
typedef struct TransCon {
@@ -677,6 +683,7 @@ bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
+void freeSnapping(struct TransInfo *t);
void applyProject(TransInfo *t);
void applyGridAbsolute(TransInfo *t);
void applySnapping(TransInfo *t, float *vec);
@@ -786,4 +793,8 @@ void projectVertSlideData(TransInfo *t, bool is_final);
/* TODO. transform_queries.c */
bool checkUseAxisMatrix(TransInfo *t);
+#define TRANSFORM_DIST_MAX_PX 1000.0f
+#define TRANSFORM_SNAP_MAX_PX 100.0f
+#define TRANSFORM_DIST_INVALID -FLT_MAX
+
#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index beeba7cf10f..13cc0c22778 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -267,9 +267,9 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
/* possible some values become nan when
* viewpoint and object are both zero */
- if (!finite(out[0])) out[0] = 0.0f;
- if (!finite(out[1])) out[1] = 0.0f;
- if (!finite(out[2])) out[2] = 0.0f;
+ if (!isfinite(out[0])) out[0] = 0.0f;
+ if (!isfinite(out[1])) out[1] = 0.0f;
+ if (!isfinite(out[2])) out[2] = 0.0f;
}
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 5d3e71c5a3c..fa5e86813fa 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -820,6 +820,7 @@ static void pose_grab_with_ik_clear(Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
+ bool need_dependency_update = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -834,6 +835,7 @@ static void pose_grab_with_ik_clear(Object *ob)
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
/* iTaSC needs clear for removed constraints */
+ need_dependency_update = true;
BIK_clear_data(ob->pose);
BLI_remlink(&pchan->constraints, con);
@@ -849,10 +851,10 @@ static void pose_grab_with_ik_clear(Object *ob)
}
#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy())
+ if (!DEG_depsgraph_use_legacy() && need_dependency_update)
#endif
{
- /* TODO(sergey): Consuder doing partial update only. */
+ /* TODO(sergey): Consider doing partial update only. */
DAG_relations_tag_update(G.main);
}
}
@@ -7813,7 +7815,9 @@ static void createTransGPencil(bContext *C, TransInfo *t)
copy_m3_m3(td->mtx, mtx);
unit_m3(td->axismtx); // XXX?
}
-
+ /* Triangulation must be calculated again, so save the stroke for recalc function */
+ td->extra = gps;
+
td++;
tail++;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index eb6308d1c41..ed6477392d8 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -969,6 +969,16 @@ static void recalcData_sequencer(TransInfo *t)
flushTransSeq(t);
}
+/* force recalculation of triangles during transformation */
+static void recalcData_gpencil_strokes(TransInfo *t)
+ {
+ TransData *td = t->data;
+ for (int i = 0; i < t->total; i++, td++) {
+ bGPDstroke *gps = td->extra;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+}
+
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -983,7 +993,8 @@ void recalcData(TransInfo *t)
flushTransPaintCurve(t);
}
else if (t->options & CTX_GPENCIL_STROKES) {
- /* pass? */
+ /* set recalc triangle cache flag */
+ recalcData_gpencil_strokes(t);
}
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
@@ -1502,6 +1513,8 @@ void postTrans(bContext *C, TransInfo *t)
if (t->mouse.data) {
MEM_freeN(t->mouse.data);
}
+
+ freeSnapping(t);
}
void applyTransObjects(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index bb9120c337b..38f1d37acd6 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -36,8 +36,6 @@
#include "PIL_time.h"
-#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h" /* Temporary, for snapping to other unselected meshes */
@@ -61,17 +59,16 @@
#include "BKE_editmesh.h"
#include "BKE_sequencer.h"
#include "BKE_main.h"
-#include "BKE_tracking.h"
#include "RNA_access.h"
#include "WM_types.h"
-#include "ED_armature.h"
#include "ED_image.h"
#include "ED_node.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
+#include "ED_transform_snap_object_context.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -83,10 +80,6 @@
/* this should be passed as an arg for use in snap functions */
#undef BASACT
-#define TRANSFORM_DIST_MAX_PX 1000.0f
-#define TRANSFORM_SNAP_MAX_PX 100.0f
-#define TRANSFORM_DIST_INVALID -FLT_MAX
-
/* use half of flt-max so we can scale up without an exception */
/********************* PROTOTYPES ***********************/
@@ -331,8 +324,8 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (snapObjectsTransform(
- t, mval_fl, t->tsnap.modeSelect,
- loc, no, &dist_px))
+ t, mval_fl, t->tsnap.modeSelect, &dist_px,
+ loc, no))
{
// if (t->flag & (T_EDIT|T_POSE)) {
// mul_m4_v3(imat, loc);
@@ -493,6 +486,35 @@ bool validSnappingNormal(TransInfo *t)
return false;
}
+static bool bm_edge_is_snap_target(BMEdge *e, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT | BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT | BM_ELEM_HIDDEN)) {
+ return false;
+ }
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
+ return false;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return true;
+}
+
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -573,6 +595,21 @@ static void initSnappingMode(TransInfo *t)
/* Always grid outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->tsnap.object_context == NULL) {
+ t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
+ G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ t->ar, t->view);
+
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ bm_edge_is_snap_target,
+ bm_face_is_snap_target,
+ SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
+ }
+ }
}
void initSnapping(TransInfo *t, wmOperator *op)
@@ -636,6 +673,14 @@ void initSnapping(TransInfo *t, wmOperator *op)
initSnappingMode(t);
}
+void freeSnapping(TransInfo *t)
+{
+ if (t->tsnap.object_context) {
+ ED_transform_snap_object_context_destroy(t->tsnap.object_context);
+ t->tsnap.object_context = NULL;
+ }
+}
+
static void setSnappingCallback(TransInfo *t)
{
t->tsnap.calcSnap = CalcSnapGeometry;
@@ -918,92 +963,16 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
mval[1] = t->mval[1];
if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
- ListBase depth_peels;
- DepthPeel *p1, *p2;
- const float *last_p = NULL;
- float max_dist = FLT_MAX;
- float p[3] = {0.0f, 0.0f, 0.0f};
-
- BLI_listbase_clear(&depth_peels);
-
- peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels);
-
-// if (LAST_SNAP_POINT_VALID)
-// {
-// last_p = LAST_SNAP_POINT;
-// }
-// else
- {
- last_p = t->tsnap.snapPoint;
- }
-
-
- for (p1 = depth_peels.first; p1; p1 = p1->next) {
- if (p1->flag == 0) {
- float vec[3];
- float new_dist;
-
- p2 = NULL;
- p1->flag = 1;
-
- /* if peeling objects, take the first and last from each object */
- if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) {
- DepthPeel *peel;
- for (peel = p1->next; peel; peel = peel->next) {
- if (peel->ob == p1->ob) {
- peel->flag = 1;
- p2 = peel;
- }
- }
- }
- /* otherwise, pair first with second and so on */
- else {
- for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) {
- /* nothing to do here */
- }
- }
-
- if (p2) {
- p2->flag = 1;
-
- add_v3_v3v3(vec, p1->p, p2->p);
- mul_v3_fl(vec, 0.5f);
- }
- else {
- copy_v3_v3(vec, p1->p);
- }
-
- if (last_p == NULL) {
- copy_v3_v3(p, vec);
- max_dist = 0;
- break;
- }
-
- new_dist = len_squared_v3v3(last_p, vec);
-
- if (new_dist < max_dist) {
- copy_v3_v3(p, vec);
- max_dist = new_dist;
- }
- }
- }
-
- if (max_dist != FLT_MAX) {
- copy_v3_v3(loc, p);
- /* XXX, is there a correct normal in this case ???, for now just z up */
- no[0] = 0.0;
- no[1] = 0.0;
- no[2] = 1.0;
- found = true;
- }
-
- BLI_freelistN(&depth_peels);
+ found = peelObjectsTransform(
+ t, mval, t->tsnap.modeSelect,
+ (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
+ loc, no, NULL);
}
else {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
- t, mval, t->tsnap.modeSelect,
- loc, no, &dist_px);
+ t, mval, t->tsnap.modeSelect, &dist_px,
+ loc, no);
}
if (found == true) {
@@ -1237,1142 +1206,107 @@ static void TargetSnapClosest(TransInfo *t)
}
}
-static bool snapEdge(
- ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
- int result;
- bool retval = false;
-
- copy_v3_v3(ray_end, ray_normal_local);
- mul_v3_fl(ray_end, 2000);
- add_v3_v3v3(ray_end, ray_start_local, ray_end);
-
- result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
-
- if (result) {
- float edge_loc[3], vec[3];
- float mul;
-
- /* check for behind ray_start */
- sub_v3_v3v3(dvec, intersect, ray_start_local);
-
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
-
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
-
- if (mul > 1) {
- mul = 1;
- copy_v3_v3(intersect, v1co);
- }
- else if (mul < 0) {
- mul = 0;
- copy_v3_v3(intersect, v2co);
- }
-
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
-
- copy_v3_v3(location, intersect);
-
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
-
- /* 10% threshold if edge is closer but a bit further
- * this takes care of series of connected edges a bit slanted w.r.t the viewport
- * otherwise, it would stick to the verts of the closest edge and not slide along merrily
- * */
- if (new_dist <= *r_dist_px && new_depth < *ray_depth * 1.001f) {
- float n1[3], n2[3];
-
- *ray_depth = new_depth;
- retval = true;
-
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
-
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
-
- if (r_no) {
- normal_short_to_float_v3(n1, v1no);
- normal_short_to_float_v3(n2, v2no);
- interp_v3_v3v3(r_no, n2, n1, mul);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- copy_v3_v3(r_loc, location);
-
- *r_dist_px = new_dist;
- }
- }
- }
-
- return retval;
-}
-
-static bool snapVertex(
- ARegion *ar, const float vco[3], const short vno[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- bool retval = false;
- float dvec[3];
-
- sub_v3_v3v3(dvec, vco, ray_start_local);
-
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
-
- copy_v3_v3(location, vco);
-
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
-
-
- if (new_dist <= *r_dist_px && new_depth < *ray_depth) {
- *ray_depth = new_depth;
- retval = true;
-
- copy_v3_v3(r_loc, location);
-
- if (r_no) {
- normal_short_to_float_v3(r_no, vno);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- *r_dist_px = new_dist;
- }
- }
-
- return retval;
-}
-
-static bool snapArmature(
- ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- if (arm->edbo) {
- EditBone *eBone;
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->layer & arm->layer) {
- /* skip hidden or moving (selected) bones */
- if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- }
- }
- }
- }
- }
- else if (ob->pose && ob->pose->chanbase.first) {
- bPoseChannel *pchan;
- Bone *bone;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- /* skip hidden bones */
- if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
- const float *head_vec = pchan->pose_head;
- const float *tail_vec = pchan->pose_tail;
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- break;
- }
- }
- }
- }
-
- return retval;
-}
-
-static bool snapCurve(
- ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
- int u;
-
- Nurb *nu;
-
- /* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
- for (u = 0; u < nu->pntsu; u++) {
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- if (ob->mode == OB_MODE_EDIT) {
- if (nu->bezt) {
- /* don't snap to selected (moving) or hidden */
- if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
- break;
- }
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
- if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- else {
- /* don't snap to selected (moving) or hidden */
- if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
- break;
- }
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- else {
- /* curve is not visible outside editmode if nurb length less than two */
- if (nu->pntsu > 1) {
- if (nu->bezt) {
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- else {
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
- }
- }
- }
- break;
- }
- default:
- break;
- }
- }
- }
- return retval;
-}
-
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
-{
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+bool snapObjectsTransform(
+ TransInfo *t, const float mval[2], SnapSelect snap_select,
+ float *dist_px,
+ float r_loc[3], float r_no[3])
+{
+ return ED_transform_snap_object_project_view3d_ex(
+ t->tsnap.object_context,
+ &(const struct SnapObjectParams){
+ .snap_select = snap_select,
+ .snap_to = t->scene->toolsettings->snap_mode,
+ .use_object_edit = (t->flag & T_EDIT) != 0,
+ .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0,
+ },
+ mval, dist_px, NULL,
+ r_loc, r_no, NULL);
}
-static bool snapDerivedMesh(
- ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float mval[2], const short snap_to, bool do_bb,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
-{
- bool retval = false;
- int totvert = dm->getNumVerts(dm);
-
- if (totvert > 0) {
- const bool do_ray_start_correction = (
- ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
- (ar && !((RegionView3D *)ar->regiondata)->is_persp));
- bool need_ray_start_correction_init = do_ray_start_correction;
-
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
-
- BVHTreeFromMesh treedata = {0};
-
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- /* local scale in normal direction */
- local_scale = normalize_v3(ray_normal_local);
- local_depth = *ray_depth;
- if (local_depth != BVH_RAYCAST_DIST_MAX) {
- local_depth *= local_scale;
- }
- if (do_bb) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (bb) {
- BoundBox bb_temp;
-
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
- * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
- bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
-
- /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'r_dist_px'),
- * scale up so we can snap against verts & edges on the boundbox, see T46816. */
- if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
- BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
- bb = &bb_temp;
- }
-
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
+/******************** PEELING *********************************/
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
- }
- need_ray_start_correction_init = false;
+bool peelObjectsSnapContext(
+ SnapObjectContext *sctx,
+ const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_thickness)
+{
+ ListBase depths_peel = {0};
+ ED_transform_snap_object_project_all_view3d_ex(
+ sctx,
+ &(const struct SnapObjectParams){
+ .snap_to = SCE_SNAP_MODE_FACE,
+ .snap_select = snap_select,
+ .use_object_edit = true,
+ },
+ mval, -1.0f, false,
+ &depths_peel);
+
+ if (!BLI_listbase_is_empty(&depths_peel)) {
+ /* At the moment we only use the hits of the first object */
+ struct SnapObjectHitDepth *hit_min = depths_peel.first;
+ for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) {
+ if (iter->depth < hit_min->depth) {
+ hit_min = iter;
}
}
+ struct SnapObjectHitDepth *hit_max = NULL;
- treedata.em_evil = em;
- treedata.em_evil_all = false;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- bvhtree_from_mesh_looptri(&treedata, dm, 0.0f, 4, 6);
- break;
- case SCE_SNAP_MODE_VERTEX:
- bvhtree_from_mesh_verts(&treedata, dm, 0.0f, 2, 6);
- break;
- }
-
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
-
- if (treedata.tree != NULL) {
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata.tree, ray_start_local, &nearest, treedata.nearest_callback, &treedata);
- if (nearest.index != -1) {
- len_diff = sqrtf(nearest.dist_sq);
+ if (use_peel_object) {
+ /* if peeling objects, take the first and last from each object */
+ hit_max = hit_min;
+ for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
+ if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) {
+ hit_max = iter;
}
}
}
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
else {
- len_diff = 0.0f;
- }
-
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- BVHTreeRayHit hit;
-
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata.tree &&
- BLI_bvhtree_ray_cast(treedata.tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata.raycast_callback, &treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
- copy_v3_v3(r_no, hit.no);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
-
- retval = true;
-
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata.looptri[hit.index]);
- }
- }
- }
- break;
- }
- case SCE_SNAP_MODE_VERTEX:
- {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata.tree &&
- BLI_bvhtree_find_nearest_to_ray(
- treedata.tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
- {
- const MVert *v = &treedata.vert[nearest.index];
- retval = snapVertex(
- ar, v->co, v->no, obmat, timat, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- break;
- }
- case SCE_SNAP_MODE_EDGE:
- {
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
- const int *index_array = NULL;
- int index = 0;
- int i;
-
- if (em != NULL) {
- index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
- }
-
- for (i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- bool test = true;
-
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- }
- else {
- index = i;
- }
-
- if (index == ORIGINDEX_NONE) {
- test = false;
- }
- else {
- BMEdge *eed = BM_edge_at_index(em->bm, index);
-
- if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
- {
- test = false;
- }
- }
- }
-
- if (test) {
- retval |= snapEdge(
- ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat,
- mval, ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- }
-
- break;
- }
- }
-
- free_bvhtree_from_mesh(&treedata);
- }
-
- return retval;
-}
-
-/* may extend later (for now just snaps to empty center) */
-static bool snapEmpty(
- ARegion *ar, Object *ob, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
- bool retval = false;
-
- if (ob->transflag & OB_DUPLI) {
- return retval;
- }
- /* for now only vertex supported */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- const float zero_co[3] = {0.0f};
- retval |= snapVertex(
- ar, zero_co, NULL, obmat, NULL, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL, r_dist_px);
- break;
- }
- default:
- break;
- }
-
- return retval;
-}
-
-static bool snapCamera(
- ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
-{
- float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
- bool retval = false;
- MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
- MovieTracking *tracking;
- float ray_start_local[3], ray_normal_local[3];
-
- if (clip == NULL) {
- return retval;
- }
- if (object->transflag & OB_DUPLI) {
- return retval;
- }
-
- tracking = &clip->tracking;
-
- BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
-
- invert_m4_m4(orig_camera_imat, orig_camera_mat);
- invert_m4_m4(imat, obmat);
-
- switch (snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- MovieTrackingObject *tracking_object;
-
- for (tracking_object = tracking->objects.first;
- tracking_object;
- tracking_object = tracking_object->next)
- {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- MovieTrackingTrack *track;
- float reconstructed_camera_mat[4][4],
- reconstructed_camera_imat[4][4];
- float (*vertex_obmat)[4];
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
- CFRA, reconstructed_camera_mat);
-
- invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
- }
-
- for (track = tracksbase->first; track; track = track->next) {
- float bundle_pos[3];
-
- if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
- continue;
- }
-
- copy_v3_v3(bundle_pos, track->bundle_pos);
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_m4_v3(orig_camera_imat, ray_start_local);
- mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
- vertex_obmat = orig_camera_mat;
+ /* otherwise, pair first with second and so on */
+ for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
+ if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) {
+ if (hit_max == NULL) {
+ hit_max = iter;
}
- else {
- mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
- vertex_obmat = obmat;
+ else if (iter->depth < hit_max->depth) {
+ hit_max = iter;
}
-
- retval |= snapVertex(
- ar, bundle_pos, NULL, vertex_obmat, NULL, mval,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL, r_dist_px);
}
}
-
- break;
- }
- default:
- break;
- }
-
- return retval;
-}
-
-static bool snapObject(
- Scene *scene, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit,
- const float mval[2], const short snap_to,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- bool retval = false;
-
- if (ob->type == OB_MESH) {
- BMEditMesh *em;
- DerivedMesh *dm;
- bool do_bb = true;
-
- if (use_obedit) {
- em = BKE_editmesh_from_object(ob);
- dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
- do_bb = false;
- }
- else {
- /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
- * still set the 'em' to NULL, since we only want the 'dm'. */
- em = BKE_editmesh_from_object(ob);
- if (em) {
- editbmesh_get_derived_cage_and_final(scene, ob, em, CD_MASK_BAREMESH, &dm);
- }
- else {
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ /* in this case has only one hit. treat as raycast */
+ if (hit_max == NULL) {
+ hit_max = hit_min;
}
- em = NULL;
}
-
- retval = snapDerivedMesh(
- ar, ob, dm, em, obmat, mval, snap_to, do_bb,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index);
-
- dm->release(dm);
- }
- else if (ob->type == OB_ARMATURE) {
- retval = snapArmature(
- ar, ob, ob->data, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_CURVE) {
- retval = snapCurve(
- ar, ob, ob->data, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_EMPTY) {
- retval = snapEmpty(
- ar, ob, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
- else if (ob->type == OB_CAMERA) {
- retval = snapCamera(
- ar, scene, ob, obmat, mval, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no, r_dist_px);
- }
-
- if (retval) {
- if (r_ob) {
- *r_ob = ob;
- copy_m4_m4(r_obmat, obmat);
- }
- }
- return retval;
-}
+ mid_v3_v3v3(r_loc, hit_min->co, hit_max->co);
-static bool snapObjectsRay(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
- /* return args */
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- Base *base;
- bool retval = false;
-
- if (snap_select == SNAP_ALL && obedit) {
- Object *ob = obedit;
-
- retval |= snapObject(
- scene, ar, ob, ob->obmat, true,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
- * which makes the loop skip it, even the derived mesh will never change
- *
- * To solve that problem, we do it first as an exception.
- * */
- base = base_act;
- if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base->object;
- retval |= snapObject(
- scene, ar, ob, ob->obmat, false,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- for (base = FIRSTBASE; base != NULL; base = base->next) {
- if ((BASE_VISIBLE_BGMODE(v3d, scene, base)) &&
- (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
-
- ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
- {
- Object *ob = base->object;
- Object *ob_snap = ob;
- bool use_obedit = false;
-
- /* for linked objects, use the same object but a different matrix */
- if (obedit && ob->data == obedit->data) {
- use_obedit = true;
- ob_snap = obedit;
- }
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
- Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
-
- retval |= snapObject(
- scene, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
- }
-
- free_object_duplilist(lb);
- }
-
- retval |= snapObject(
- scene, ar, ob_snap, ob->obmat, use_obedit,
- mval, snap_to,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
+ if (r_thickness) {
+ *r_thickness = hit_max->depth - hit_min->depth;
}
- }
-
- return retval;
-}
-static bool snapObjects(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
-{
- float ray_start[3], ray_normal[3], ray_orgigin[3];
-
- if (!ED_view3d_win_to_ray_ex(ar, v3d, mval, ray_orgigin, ray_normal, ray_start, true)) {
- return false;
- }
-
- return snapObjectsRay(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_start, ray_normal, ray_orgigin, ray_depth,
- r_loc, r_no, r_dist_px, r_index, NULL, NULL);
-}
-bool snapObjectsTransform(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- float ray_dist = BVH_RAYCAST_DIST_MAX;
- Object *obedit = NULL;
- Base *base_act = NULL;
+ /* XXX, is there a correct normal in this case ???, for now just z up */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
- if (t->flag & T_EDIT) {
- obedit = t->obedit;
+ BLI_freelistN(&depths_peel);
+ return true;
}
-
- if ((t->options & CTX_GPENCIL_STROKES) == 0) {
- base_act = t->scene->basact;
- }
-
- return snapObjects(
- t->scene, t->view, t->ar, base_act, obedit,
- mval, snap_select, t->scene->toolsettings->snap_mode,
- &ray_dist,
- r_loc, r_no, r_dist_px, NULL);
-}
-
-bool snapObjectsContext(
- bContext *C, const float mval[2], SnapSelect snap_select,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
- float ray_dist = BVH_RAYCAST_DIST_MAX;
-
- return snapObjects(
- scene, v3d, ar, scene->basact, obedit,
- mval, snap_select, scene->toolsettings->snap_mode,
- &ray_dist,
- r_loc, r_no, r_dist_px, NULL);
-}
-
-bool snapObjectsEx(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px)
-{
- return snapObjects(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_depth,
- r_loc, r_no, r_dist_px, NULL);
-}
-bool snapObjectsRayEx(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
- const float mval[2], SnapSelect snap_select, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
- float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- return snapObjectsRay(
- scene, v3d, ar, base_act, obedit,
- mval, snap_select, snap_to,
- ray_start, ray_normal, ray_start, ray_depth,
- r_loc, r_no, r_dist_px, r_index,
- r_ob, r_obmat);
-}
-
-/******************** PEELING *********************************/
-
-
-static int cmpPeel(const void *arg1, const void *arg2)
-{
- const DepthPeel *p1 = arg1;
- const DepthPeel *p2 = arg2;
- int val = 0;
-
- if (p1->depth < p2->depth) {
- val = -1;
- }
- else if (p1->depth > p2->depth) {
- val = 1;
- }
-
- return val;
-}
-
-static void removeDoublesPeel(ListBase *depth_peels)
-{
- DepthPeel *peel;
-
- for (peel = depth_peels->first; peel; peel = peel->next) {
- DepthPeel *next_peel = peel->next;
-
- if (next_peel && fabsf(peel->depth - next_peel->depth) < 0.0015f) {
- peel->next = next_peel->next;
-
- if (next_peel->next) {
- next_peel->next->prev = peel;
- }
-
- MEM_freeN(next_peel);
- }
- }
-}
-
-static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
-{
- DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
-
- peel->depth = depth;
- peel->ob = ob;
- copy_v3_v3(peel->p, p);
- copy_v3_v3(peel->no, no);
-
- BLI_addtail(depth_peels, peel);
-
- peel->flag = 0;
-}
-
-struct PeelRayCast_Data {
- BVHTreeFromMesh bvhdata;
-
- /* internal vars for adding peel */
- Object *ob;
- const float (*obmat)[4];
- const float (*timat)[3];
-
- const float *ray_start; /* globalspace */
-
- const MLoopTri *looptri;
- const float (*polynors)[3]; /* optional, can be NULL */
-
- /* output list */
- ListBase *depth_peels;
-};
-
-static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
-{
- struct PeelRayCast_Data *data = userdata;
-
- data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
-
- if (hit->index != -1) {
- /* get all values in worldspace */
- float location[3], normal[3];
- float depth;
-
- /* worldspace location */
- mul_v3_m4v3(location, (float (*)[4])data->obmat, hit->co);
- depth = len_v3v3(location, data->ray_start);
-
- /* worldspace normal */
- copy_v3_v3(normal, data->polynors ? data->polynors[data->looptri[hit->index].poly] : hit->no);
- mul_m3_v3((float (*)[3])data->timat, normal);
- normalize_v3(normal);
-
- addDepthPeel(data->depth_peels, depth, location, normal, data->ob);
- }
-}
-
-static bool peelDerivedMesh(
- Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
- ListBase *depth_peels)
-{
- bool retval = false;
- int totvert = dm->getNumVerts(dm);
-
- if (totvert > 0) {
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- const int looptri_num = dm->getNumLoopTri(dm);
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- bool test = true;
-
- invert_m4_m4(imat, obmat);
-
- transpose_m3_m4(timat, imat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
- /* If number of vert is more than an arbitrary limit,
- * test against boundbox first
- * */
- if (looptri_num > 16) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (bb) {
- BoundBox bb_temp;
-
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
- * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
- bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
-
- test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL);
- }
- }
-
- if (test == true) {
- struct PeelRayCast_Data data;
-
- data.bvhdata.em_evil = em;
- data.bvhdata.em_evil_all = false;
- bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6);
-
- if (data.bvhdata.tree != NULL) {
- data.ob = ob;
- data.obmat = (const float (*)[4])obmat;
- data.timat = (const float (*)[3])timat;
- data.ray_start = ray_start;
- data.looptri = looptri;
- data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
- data.depth_peels = depth_peels;
-
- BLI_bvhtree_ray_cast_all(data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f,
- peelRayCast_cb, &data);
- }
-
- free_bvhtree_from_mesh(&data.bvhdata);
- }
- }
-
- return retval;
-}
-
-static bool peelObjects(
- Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
- const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
-{
- Base *base;
- bool retval = false;
- float ray_start[3], ray_normal[3];
-
- if (ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal, true) == false) {
- return false;
- }
-
- for (base = scene->base.first; base != NULL; base = base->next) {
- if (BASE_SELECTABLE(v3d, base)) {
- Object *ob = base->object;
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- Object *dob = dupli_ob->ob;
-
- if (dob->type == OB_MESH) {
- BMEditMesh *em;
- DerivedMesh *dm = NULL;
- bool val;
-
- if (dob != obedit) {
- dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- }
- else {
- em = BKE_editmesh_from_object(dob);
- dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- }
-
- retval = retval || val;
-
- dm->release(dm);
- }
- }
-
- free_object_duplilist(lb);
- }
-
- if (ob->type == OB_MESH) {
- bool val = false;
-
- if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) {
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- dm->release(dm);
- }
- else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) {
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
-
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
- dm->release(dm);
- }
-
- retval = retval || val;
-
- }
- }
- }
-
- BLI_listbase_sort(r_depth_peels, cmpPeel);
- removeDoublesPeel(r_depth_peels);
-
- return retval;
-}
-
-bool peelObjectsTransForm(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
-{
- return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels);
+ return false;
}
-bool peelObjectsContext(
- bContext *C, const float mval[2], SnapSelect snap_select,
- ListBase *r_depth_peels)
+bool peelObjectsTransform(
+ TransInfo *t,
+ const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_thickness)
{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
-
- return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels);
+ return peelObjectsSnapContext(
+ t->tsnap.object_context,
+ mval, snap_select, use_peel_object,
+ r_loc, r_no, r_thickness);
}
/******************** NODES ***********************************/
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
new file mode 100644
index 00000000000..62ca4e515a5
--- /dev/null
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -0,0 +1,1767 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_snap_object.c
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_anim.h" /* for duplis */
+#include "BKE_editmesh.h"
+#include "BKE_main.h"
+#include "BKE_tracking.h"
+
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+#include "ED_armature.h"
+
+#include "transform.h"
+
+typedef struct SnapObjectData {
+ enum {
+ SNAP_MESH = 1,
+ SNAP_EDIT_MESH,
+ } type;
+} SnapObjectData;
+
+typedef struct SnapObjectData_Mesh {
+ SnapObjectData sd;
+ BVHTreeFromMesh *bvh_trees[2];
+
+} SnapObjectData_Mesh;
+
+typedef struct SnapObjectData_EditMesh {
+ SnapObjectData sd;
+ BVHTreeFromEditMesh *bvh_trees[2];
+
+} SnapObjectData_EditMesh;
+
+struct SnapObjectContext {
+ Main *bmain;
+ Scene *scene;
+ int flag;
+
+ /* Optional: when performing screen-space projection.
+ * otherwise this doesn't take viewport into account. */
+ bool use_v3d;
+ struct {
+ struct View3D *v3d;
+ struct ARegion *ar;
+ } v3d_data;
+
+
+ /* Object -> SnapObjectData map */
+ struct {
+ GHash *object_map;
+ MemArena *mem_arena;
+ } cache;
+
+ /* Filter data, returns true to check this value */
+ struct {
+ struct {
+ bool (*test_vert_fn)(BMVert *, void *user_data);
+ bool (*test_edge_fn)(BMEdge *, void *user_data);
+ bool (*test_face_fn)(BMFace *, void *user_data);
+ void *user_data;
+ } edit_mesh;
+ } callbacks;
+
+};
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Support for storing all depths, not just the first (raycast 'all')
+ *
+ * This uses a list of #SnapObjectHitDepth structs.
+ *
+ * \{ */
+
+/* Store all ray-hits */
+struct RayCastAll_Data {
+ void *bvhdata;
+
+ /* internal vars for adding depths */
+ BVHTree_RayCastCallback raycast_callback;
+
+ const float(*obmat)[4];
+ const float(*timat)[3];
+
+ float len_diff;
+ float local_scale;
+
+ Object *ob;
+ unsigned int ob_uuid;
+
+ /* DerivedMesh only */
+ DerivedMesh *dm;
+ const struct MLoopTri *dm_looptri;
+
+ /* output data */
+ ListBase *hit_list;
+ bool retval;
+};
+
+static struct SnapObjectHitDepth *hit_depth_create(
+ const float depth, const float co[3], const float no[3], int index,
+ Object *ob, const float obmat[4][4], unsigned int ob_uuid)
+{
+ struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
+
+ hit->depth = depth;
+ copy_v3_v3(hit->co, co);
+ copy_v3_v3(hit->no, no);
+ hit->index = index;
+
+ hit->ob = ob;
+ copy_m4_m4(hit->obmat, (float(*)[4])obmat);
+ hit->ob_uuid = ob_uuid;
+
+ return hit;
+}
+
+static int hit_depth_cmp(const void *arg1, const void *arg2)
+{
+ const struct SnapObjectHitDepth *h1 = arg1;
+ const struct SnapObjectHitDepth *h2 = arg2;
+ int val = 0;
+
+ if (h1->depth < h2->depth) {
+ val = -1;
+ }
+ else if (h1->depth > h2->depth) {
+ val = 1;
+ }
+
+ return val;
+}
+
+static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ struct RayCastAll_Data *data = userdata;
+ data->raycast_callback(data->bvhdata, index, ray, hit);
+ if (hit->index != -1) {
+ /* get all values in worldspace */
+ float location[3], normal[3];
+ float depth;
+
+ /* worldspace location */
+ mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
+ depth = (hit->dist + data->len_diff) / data->local_scale;
+
+ /* worldspace normal */
+ copy_v3_v3(normal, hit->no);
+ mul_m3_v3((float(*)[3])data->timat, normal);
+ normalize_v3(normal);
+
+ /* currently unused, and causes issues when looptri's havn't been calculated.
+ * since theres some overhead in ensuring this data is valid, it may need to be optional. */
+#if 0
+ if (data->dm) {
+ hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]);
+ }
+#endif
+
+ struct SnapObjectHitDepth *hit_item = hit_depth_create(
+ depth, location, normal, hit->index,
+ data->ob, data->obmat, data->ob_uuid);
+ BLI_addtail(data->hit_list, hit_item);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Internal Object Snapping API
+ * \{ */
+
+static bool snapEdge(
+ ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
+ int result;
+ bool retval = false;
+
+ copy_v3_v3(ray_end, ray_normal_local);
+ mul_v3_fl(ray_end, 2000);
+ add_v3_v3v3(ray_end, ray_start_local, ray_end);
+
+ /* dvec used but we don't care about result */
+ result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec);
+
+ if (result) {
+ float edge_loc[3], vec[3];
+ float mul;
+
+ /* check for behind ray_start */
+ sub_v3_v3v3(dvec, intersect, ray_start_local);
+
+ sub_v3_v3v3(edge_loc, v1co, v2co);
+ sub_v3_v3v3(vec, intersect, v2co);
+
+ mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+
+ if (mul > 1) {
+ mul = 1;
+ copy_v3_v3(intersect, v1co);
+ }
+ else if (mul < 0) {
+ mul = 0;
+ copy_v3_v3(intersect, v2co);
+ }
+
+ if (dot_v3v3(ray_normal_local, dvec) > 0) {
+ float location[3];
+ float new_depth;
+ float screen_loc[2];
+ float new_dist;
+
+ copy_v3_v3(location, intersect);
+
+ mul_m4_v3(obmat, location);
+
+ new_depth = len_v3v3(location, ray_start);
+
+ if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
+ }
+ else {
+ new_dist = TRANSFORM_DIST_MAX_PX;
+ }
+
+ /* 10% threshold if edge is closer but a bit further
+ * this takes care of series of connected edges a bit slanted w.r.t the viewport
+ * otherwise, it would stick to the verts of the closest edge and not slide along merrily
+ * */
+ if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) {
+ float n1[3], n2[3];
+
+ *ray_depth = new_depth;
+ retval = true;
+
+ sub_v3_v3v3(edge_loc, v1co, v2co);
+ sub_v3_v3v3(vec, intersect, v2co);
+
+ mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+
+ if (r_no) {
+ normal_short_to_float_v3(n1, v1no);
+ normal_short_to_float_v3(n2, v2no);
+ interp_v3_v3v3(r_no, n2, n1, mul);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ copy_v3_v3(r_loc, location);
+
+ *dist_px = new_dist;
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapVertex(
+ ARegion *ar, const float vco[3], const float vno[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ bool retval = false;
+ float dvec[3];
+
+ sub_v3_v3v3(dvec, vco, ray_start_local);
+
+ if (dot_v3v3(ray_normal_local, dvec) > 0) {
+ float location[3];
+ float new_depth;
+ float screen_loc[2];
+ float new_dist;
+
+ copy_v3_v3(location, vco);
+
+ mul_m4_v3(obmat, location);
+
+ new_depth = len_v3v3(location, ray_start);
+
+ if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
+ }
+ else {
+ new_dist = TRANSFORM_DIST_MAX_PX;
+ }
+
+
+ if (new_dist <= *dist_px && new_depth < *ray_depth) {
+ *ray_depth = new_depth;
+ retval = true;
+
+ copy_v3_v3(r_loc, location);
+
+ if (r_no) {
+ copy_v3_v3(r_no, vno);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ *dist_px = new_dist;
+ }
+ }
+
+ return retval;
+}
+
+static bool snapArmature(
+ ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+
+ invert_m4_m4(imat, obmat);
+
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+
+ if (arm->edbo) {
+ EditBone *eBone;
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->layer & arm->layer) {
+ /* skip hidden or moving (selected) bones */
+ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(
+ ar, eBone->head, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ retval |= snapVertex(
+ ar, eBone->tail, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(
+ ar, eBone->head, NULL, eBone->tail, NULL,
+ obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (ob->pose && ob->pose->chanbase.first) {
+ bPoseChannel *pchan;
+ Bone *bone;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ /* skip hidden bones */
+ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ const float *head_vec = pchan->pose_head;
+ const float *tail_vec = pchan->pose_tail;
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(
+ ar, head_vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ retval |= snapVertex(
+ ar, tail_vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(
+ ar, head_vec, NULL, tail_vec, NULL,
+ obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, r_loc, NULL);
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapCurve(
+ ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+ int u;
+
+ Nurb *nu;
+
+ /* only vertex snapping mode (eg control points and handles) supported for now) */
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ return retval;
+ }
+
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
+ for (u = 0; u < nu->pntsu; u++) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ if (ob->mode == OB_MODE_EDIT) {
+ if (nu->bezt) {
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
+ break;
+ }
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
+ if (!(nu->bezt[u].f1 & SELECT) &&
+ !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
+ {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ if (!(nu->bezt[u].f3 & SELECT) &&
+ !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
+ {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ else {
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
+ break;
+ }
+ retval |= snapVertex(
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ else {
+ /* curve is not visible outside editmode if nurb length less than two */
+ if (nu->pntsu > 1) {
+ if (nu->bezt) {
+ retval |= snapVertex(
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ else {
+ retval |= snapVertex(
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+/* may extend later (for now just snaps to empty center) */
+static bool snapEmpty(
+ ARegion *ar, Object *ob, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ bool retval = false;
+
+ if (ob->transflag & OB_DUPLI) {
+ return retval;
+ }
+ /* for now only vertex supported */
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ return retval;
+ }
+
+ invert_m4_m4(imat, obmat);
+
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ const float zero_co[3] = {0.0f};
+ retval |= snapVertex(
+ ar, zero_co, NULL, obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static bool snapCamera(
+ ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no))
+{
+ float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
+ bool retval = false;
+ MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
+ MovieTracking *tracking;
+ float ray_start_local[3], ray_normal_local[3];
+
+ if (clip == NULL) {
+ return retval;
+ }
+ if (object->transflag & OB_DUPLI) {
+ return retval;
+ }
+
+ tracking = &clip->tracking;
+
+ BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
+
+ invert_m4_m4(orig_camera_imat, orig_camera_mat);
+ invert_m4_m4(imat, obmat);
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ MovieTrackingObject *tracking_object;
+
+ for (tracking_object = tracking->objects.first;
+ tracking_object;
+ tracking_object = tracking_object->next)
+ {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ float reconstructed_camera_mat[4][4],
+ reconstructed_camera_imat[4][4];
+ float (*vertex_obmat)[4];
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
+ CFRA, reconstructed_camera_mat);
+
+ invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
+ }
+
+ for (track = tracksbase->first; track; track = track->next) {
+ float bundle_pos[3];
+
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
+ }
+
+ copy_v3_v3(bundle_pos, track->bundle_pos);
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ mul_m4_v3(orig_camera_imat, ray_start_local);
+ mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
+ vertex_obmat = orig_camera_mat;
+ }
+ else {
+ mul_m4_v3(reconstructed_camera_imat, bundle_pos);
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+ vertex_obmat = obmat;
+ }
+
+ retval |= snapVertex(
+ ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL);
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
+{
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+}
+
+static bool snapDerivedMesh(
+ SnapObjectContext *sctx,
+ Object *ob, DerivedMesh *dm, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to, bool do_bb,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth, unsigned int ob_index,
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (dm->getNumPolys(dm) == 0) {
+ return retval;
+ }
+ }
+ if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (dm->getNumEdges(dm) == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (dm->getNumVerts(dm) == 0) {
+ return retval;
+ }
+ }
+
+ {
+ const bool do_ray_start_correction = (
+ ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
+ (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
+ bool need_ray_start_correction_init = do_ray_start_correction;
+
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ /* local scale in normal direction */
+ local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ if (do_bb) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ if (bb) {
+ BoundBox bb_temp;
+
+ /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
+ bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
+
+ /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
+ * scale up so we can snap against verts & edges on the boundbox, see T46816. */
+ if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
+ bb = &bb_temp;
+ }
+
+ /* was local_depth, see: T47838 */
+ len_diff = BVH_RAYCAST_DIST_MAX;
+
+ if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ need_ray_start_correction_init = false;
+ }
+ }
+
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata = NULL, treedata_stack;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[tree_index];
+
+ /* the tree is owned by the DM and may have been freed since we last used! */
+ if (treedata && treedata->tree) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ }
+ }
+ }
+ else {
+ if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
+ }
+ }
+
+ if (treedata && treedata->tree == NULL) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
+ break;
+ }
+ }
+
+ if (need_ray_start_correction_init) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ if (treedata && treedata->tree != NULL) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ len_diff = sqrtf(nearest.dist_sq);
+ }
+ }
+ }
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (do_ray_start_correction) {
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index,
+ data.dm = dm;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit;
+
+ hit.index = -1;
+ hit.dist = local_depth;
+
+ if (treedata->tree &&
+ BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+ copy_v3_v3(r_no, hit.no);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = local_depth * local_depth;
+ if (treedata->tree &&
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_start_local, ray_normal_local,
+ &nearest, NULL, NULL) != -1)
+ {
+ const MVert *v = &treedata->vert[nearest.index];
+ float vno[3];
+ normal_short_to_float_v3(vno, v->no);
+ retval = snapVertex(
+ ar, v->co, vno, obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_EDGE:
+ {
+ MVert *verts = dm->getVertArray(dm);
+ MEdge *edges = dm->getEdgeArray(dm);
+ int totedge = dm->getNumEdges(dm);
+
+ for (int i = 0; i < totedge; i++) {
+ MEdge *e = edges + i;
+ retval |= snapEdge(
+ ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
+ obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+
+ break;
+ }
+ }
+
+ if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
+ if (treedata) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ }
+ }
+
+ return retval;
+}
+
+
+static bool snapEditMesh(
+ SnapObjectContext *sctx,
+ Object *ob, BMEditMesh *em, float obmat[4][4],
+ const float mval[2], float *dist_px, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth, const unsigned int ob_index,
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (em->bm->totface == 0) {
+ return retval;
+ }
+ }
+ if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (em->bm->totedge == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (em->bm->totvert == 0) {
+ return retval;
+ }
+ }
+
+ {
+ const bool do_ray_start_correction = (
+ ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
+ (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
+
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff;
+
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_normal);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ /* local scale in normal direction */
+ local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ SnapObjectData_EditMesh *sod = NULL;
+
+ BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ sod = *sod_p;
+ }
+ else {
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ }
+
+ int tree_index = -1;
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ tree_index = 1;
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ tree_index = 0;
+ break;
+ }
+ if (tree_index != -1) {
+ if (sod->bvh_trees[tree_index] == NULL) {
+ sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ treedata = sod->bvh_trees[tree_index];
+ }
+ }
+ else {
+ if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
+ }
+ }
+
+ if (treedata && treedata->tree == NULL) {
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ BLI_bitmap *looptri_mask = NULL;
+ int looptri_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ em->bm, looptri_mask,
+ sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6);
+ if (looptri_mask) {
+ MEM_freeN(looptri_mask);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BLI_bitmap *verts_mask = NULL;
+ int verts_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_vert_fn) {
+ verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ verts_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_VERTS_OF_MESH, em->bm, verts_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
+ sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
+ if (verts_mask) {
+ MEM_freeN(verts_mask);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (do_ray_start_correction) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ if (treedata && treedata->tree != NULL) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ len_diff = sqrtf(nearest.dist_sq);
+ }
+ }
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ {
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.dm = NULL;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit;
+
+ hit.index = -1;
+ hit.dist = local_depth;
+
+ if (treedata->tree &&
+ BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+ copy_v3_v3(r_no, hit.no);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = hit.index;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_VERTEX:
+ {
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = local_depth * local_depth;
+ if (treedata->tree &&
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_start_local, ray_normal_local,
+ &nearest, NULL, NULL) != -1)
+ {
+ const BMVert *v = BM_vert_at_index(em->bm, nearest.index);
+ retval = snapVertex(
+ ar, v->co, v->no, obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ break;
+ }
+ case SCE_SNAP_MODE_EDGE:
+ {
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
+ int totedge = em->bm->totedge;
+ for (int i = 0; i < totedge; i++) {
+ BMEdge *eed = BM_edge_at_index(em->bm, i);
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
+ {
+ short v1no[3], v2no[3];
+ normal_float_to_short_v3(v1no, eed->v1->no);
+ normal_float_to_short_v3(v2no, eed->v2->no);
+ retval |= snapEdge(
+ ar, eed->v1->co, v1no, eed->v2->co, v2no,
+ obmat, timat, mval, dist_px,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no);
+ }
+ }
+
+ break;
+ }
+ }
+
+ if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
+ if (treedata) {
+ free_bvhtree_from_editmesh(treedata);
+ }
+ }
+ }
+
+ return retval;
+}
+
+static bool snapObject(
+ SnapObjectContext *sctx,
+ Object *ob, float obmat[4][4], bool use_obedit, const short snap_to,
+ const float mval[2], float *dist_px, const unsigned int ob_index,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
+{
+ ARegion *ar = sctx->v3d_data.ar;
+ bool retval = false;
+
+ if (ob->type == OB_MESH) {
+ BMEditMesh *em;
+
+ if (use_obedit) {
+ em = BKE_editmesh_from_object(ob);
+ retval = snapEditMesh(
+ sctx, ob, em, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_origin,
+ ray_depth, ob_index,
+ r_loc, r_no, r_index,
+ r_hit_list);
+ }
+ else {
+ /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
+ * still set the 'em' to NULL, since we only want the 'dm'. */
+ DerivedMesh *dm;
+ em = BKE_editmesh_from_object(ob);
+ if (em) {
+ editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
+ }
+ else {
+ dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ }
+ retval = snapDerivedMesh(
+ sctx, ob, dm, obmat, mval, dist_px, snap_to, true,
+ ray_start, ray_normal, ray_origin,
+ ray_depth, ob_index,
+ r_loc, r_no, r_index, r_hit_list);
+
+ dm->release(dm);
+ }
+ }
+ else if (ob->type == OB_ARMATURE) {
+ retval = snapArmature(
+ ar, ob, ob->data, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CURVE) {
+ retval = snapCurve(
+ ar, ob, ob->data, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_EMPTY) {
+ retval = snapEmpty(
+ ar, ob, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CAMERA) {
+ retval = snapCamera(
+ ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no);
+ }
+
+ if (retval) {
+ if (r_ob) {
+ *r_ob = ob;
+ copy_m4_m4(r_obmat, obmat);
+ }
+ }
+
+ return retval;
+}
+
+static bool snapObjectsRay(
+ SnapObjectContext *sctx,
+ SnapSelect snap_select, const short snap_to,
+ const float mval[2], float *dist_px,
+ /* special handling of active and edit objects */
+ Base *base_act, Object *obedit,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
+{
+ Base *base;
+ bool retval = false;
+ bool snap_obedit_first = snap_select == SNAP_ALL && obedit;
+ unsigned int ob_index = 0;
+
+ if (snap_obedit_first) {
+ Object *ob = obedit;
+
+ retval |= snapObject(
+ sctx, ob, ob->obmat, true, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ }
+
+ /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
+ * which makes the loop skip it, even the derived mesh will never change
+ *
+ * To solve that problem, we do it first as an exception.
+ * */
+ base = base_act;
+ if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
+ Object *ob = base->object;
+ retval |= snapObject(
+ sctx, ob, ob->obmat, false, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ }
+
+ for (base = sctx->scene->base.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
+ (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
+
+ ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
+ (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
+ {
+ Object *ob = base->object;
+ Object *ob_snap = ob;
+ bool use_obedit = false;
+
+ if (ob->transflag & OB_DUPLI) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob);
+
+ for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
+ bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
+ Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
+
+ retval |= snapObject(
+ sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ }
+
+ free_object_duplilist(lb);
+ }
+
+ if (obedit) {
+ if ((ob == obedit) &&
+ (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT)))
+ {
+ continue;
+ }
+
+ if (ob->data == obedit->data) {
+ /* for linked objects, use the same object but a different matrix */
+ use_obedit = true;
+ ob_snap = obedit;
+ }
+ }
+
+ retval |= snapObject(
+ sctx, ob_snap, ob->obmat, use_obedit, snap_to,
+ mval, dist_px, ob_index++,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ }
+ }
+
+ return retval;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object Snapping API
+ * \{ */
+
+SnapObjectContext *ED_transform_snap_object_context_create(
+ Main *bmain, Scene *scene, int flag)
+{
+ SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
+
+ sctx->flag = flag;
+
+ sctx->bmain = bmain;
+ sctx->scene = scene;
+
+ return sctx;
+}
+
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(
+ Main *bmain, Scene *scene, int flag,
+ /* extra args for view3d */
+ ARegion *ar, View3D *v3d)
+{
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+
+ sctx->use_v3d = true;
+ sctx->v3d_data.ar = ar;
+ sctx->v3d_data.v3d = v3d;
+
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ return sctx;
+}
+
+static void snap_object_data_free(void *sod_v)
+{
+ switch (((SnapObjectData *)sod_v)->type) {
+ case SNAP_MESH:
+ {
+ SnapObjectData_Mesh *sod = sod_v;
+ for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
+ if (sod->bvh_trees[i]) {
+ free_bvhtree_from_mesh(sod->bvh_trees[i]);
+ }
+ }
+ break;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ SnapObjectData_EditMesh *sod = sod_v;
+ for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
+ if (sod->bvh_trees[i]) {
+ free_bvhtree_from_editmesh(sod->bvh_trees[i]);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
+{
+ if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
+ BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ BLI_memarena_free(sctx->cache.mem_arena);
+ }
+
+ MEM_freeN(sctx);
+}
+
+void ED_transform_snap_object_context_set_editmesh_callbacks(
+ SnapObjectContext *sctx,
+ bool (*test_vert_fn)(BMVert *, void *user_data),
+ bool (*test_edge_fn)(BMEdge *, void *user_data),
+ bool (*test_face_fn)(BMFace *, void *user_data),
+ void *user_data)
+{
+ sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
+ sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
+ sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
+
+ sctx->callbacks.edit_mesh.user_data = user_data;
+}
+
+bool ED_transform_snap_object_project_ray_ex(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4])
+{
+ Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
+ Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
+
+ return snapObjectsRay(
+ sctx,
+ params->snap_select, params->snap_to,
+ NULL, NULL,
+ base_act, obedit,
+ ray_start, ray_normal, ray_start, ray_depth,
+ r_loc, r_no, r_index,
+ r_ob, r_obmat, NULL);
+}
+
+/**
+ * Fill in a list of all hits.
+ *
+ * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
+ * \param sort: Optionally sort the hits by depth.
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ */
+bool ED_transform_snap_object_project_ray_all(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float ray_start[3], const float ray_normal[3],
+ float ray_depth, bool sort,
+ ListBase *r_hit_list)
+{
+ Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
+ Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
+
+ if (ray_depth == -1.0f) {
+ ray_depth = BVH_RAYCAST_DIST_MAX;
+ }
+
+#ifdef DEBUG
+ float ray_depth_prev = ray_depth;
+#endif
+
+ bool retval = snapObjectsRay(
+ sctx,
+ params->snap_select, params->snap_to,
+ NULL, NULL,
+ base_act, obedit,
+ ray_start, ray_normal, ray_start, &ray_depth,
+ NULL, NULL, NULL, NULL, NULL,
+ r_hit_list);
+
+ /* meant to be readonly for 'all' hits, ensure it is */
+#ifdef DEBUG
+ BLI_assert(ray_depth_prev == ray_depth);
+#endif
+
+ if (sort) {
+ BLI_listbase_sort(r_hit_list, hit_depth_cmp);
+ }
+
+ return retval;
+}
+
+/**
+ * Convenience function for snap ray-casting.
+ *
+ * Given a ray, cast it into the scene (snapping to faces).
+ *
+ * \return Snap success
+ */
+static bool transform_snap_context_project_ray_impl(
+ SnapObjectContext *sctx,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_co[3], float r_no[3])
+{
+ bool ret;
+
+ /* try snap edge, then face if it fails */
+ ret = ED_transform_snap_object_project_ray_ex(
+ sctx,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .snap_to = SCE_SNAP_MODE_FACE,
+ .use_object_edit = (sctx->scene->obedit != NULL),
+ },
+ ray_start, ray_normal, ray_depth,
+ r_co, r_no, NULL,
+ NULL, NULL);
+
+ return ret;
+}
+
+bool ED_transform_snap_object_project_ray(
+ SnapObjectContext *sctx,
+ const float ray_origin[3], const float ray_direction[3], float *ray_depth,
+ float r_co[3], float r_no[3])
+{
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
+ }
+
+ float no_fallback[3];
+ if (r_no == NULL) {
+ r_no = no_fallback;
+ }
+
+ return transform_snap_context_project_ray_impl(
+ sctx,
+ ray_origin, ray_direction, ray_depth,
+ r_co, r_no);
+}
+
+static bool transform_snap_context_project_view3d_mixed_impl(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ bool use_depth,
+ float r_co[3], float r_no[3])
+{
+ float ray_depth = BVH_RAYCAST_DIST_MAX;
+ bool is_hit = false;
+
+ float r_no_dummy[3];
+ if (r_no == NULL) {
+ r_no = r_no_dummy;
+ }
+
+ const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
+
+ BLI_assert(params->snap_to_flag != 0);
+ BLI_assert((params->snap_to_flag & ~(1 | 2 | 4)) == 0);
+
+ struct SnapObjectParams params_temp = *params;
+
+ for (int i = 0; i < 3; i++) {
+ if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
+ if (use_depth == false) {
+ ray_depth = BVH_RAYCAST_DIST_MAX;
+ }
+
+ params_temp.snap_to = elem_type[i];
+
+ if (ED_transform_snap_object_project_view3d(
+ sctx,
+ &params_temp,
+ mval, dist_px, &ray_depth,
+ r_co, r_no))
+ {
+ is_hit = true;
+ }
+ }
+ }
+
+ return is_hit;
+}
+
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param sctx: Snap context.
+ * \param mval: 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.
+ * \param r_no: hit normal (optional).
+ * \return Snap success
+ */
+bool ED_transform_snap_object_project_view3d_mixed(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval_fl[2], float *dist_px,
+ bool use_depth,
+ float r_co[3], float r_no[3])
+{
+ return transform_snap_context_project_view3d_mixed_impl(
+ sctx,
+ params,
+ mval_fl, dist_px, use_depth,
+ r_co, r_no);
+}
+
+bool ED_transform_snap_object_project_view3d_ex(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ float r_loc[3], float r_no[3], int *r_index)
+{
+ float ray_start[3], ray_normal[3], ray_orgigin[3];
+
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
+ }
+
+ if (!ED_view3d_win_to_ray_ex(
+ sctx->v3d_data.ar, sctx->v3d_data.v3d,
+ mval, ray_orgigin, ray_normal, ray_start, true))
+ {
+ return false;
+ }
+
+ Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
+ Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
+ return snapObjectsRay(
+ sctx,
+ params->snap_select, params->snap_to,
+ mval, dist_px,
+ base_act, obedit,
+ ray_start, ray_normal, ray_orgigin, ray_depth,
+ r_loc, r_no, r_index, NULL, NULL, NULL);
+}
+
+bool ED_transform_snap_object_project_view3d(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float *ray_depth,
+ float r_loc[3], float r_no[3])
+{
+ return ED_transform_snap_object_project_view3d_ex(
+ sctx,
+ params,
+ mval, dist_px,
+ ray_depth,
+ r_loc, r_no, NULL);
+}
+
+/**
+ * see: #ED_transform_snap_object_project_ray_all
+ */
+bool ED_transform_snap_object_project_all_view3d_ex(
+ SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ float ray_depth, bool sort,
+ ListBase *r_hit_list)
+{
+ float ray_start[3], ray_normal[3];
+
+ BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE);
+
+ if (!ED_view3d_win_to_ray_ex(
+ sctx->v3d_data.ar, sctx->v3d_data.v3d,
+ mval, NULL, ray_normal, ray_start, true))
+ {
+ return false;
+ }
+
+ return ED_transform_snap_object_project_ray_all(
+ sctx,
+ params,
+ ray_start, ray_normal, ray_depth, sort,
+ r_hit_list);
+}
+
+/** \} */
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 7de788dca56..c0b30f93939 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -83,6 +83,7 @@ set(SRC
../include/ED_space_api.h
../include/ED_text.h
../include/ED_transform.h
+ ../include/ED_transform_snap_object_context.h
../include/ED_transverts.h
../include/ED_types.h
../include/ED_util.h
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index bc7a8374c73..441fd446cd6 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -40,7 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index a1853bf8daa..ee6700666c0 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -42,7 +42,7 @@
#include "BLT_translation.h"
-#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -436,7 +436,8 @@ enum {
UNDOSYSTEM_GLOBAL = 1,
UNDOSYSTEM_EDITMODE = 2,
UNDOSYSTEM_PARTICLE = 3,
- UNDOSYSTEM_IMAPAINT = 4
+ UNDOSYSTEM_IMAPAINT = 4,
+ UNDOSYSTEM_SCULPT = 5,
};
static int get_undo_system(bContext *C)
@@ -468,6 +469,10 @@ static int get_undo_system(bContext *C)
if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE))
return UNDOSYSTEM_IMAPAINT;
}
+ else if (obact->mode & OB_MODE_SCULPT) {
+ if (!ED_undo_paint_empty(UNDO_PAINT_MESH))
+ return UNDOSYSTEM_SCULPT;
+ }
}
if (U.uiflag & USER_GLOBALUNDO)
return UNDOSYSTEM_GLOBAL;
@@ -495,6 +500,9 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
else if (undosys == UNDOSYSTEM_IMAPAINT) {
name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active);
}
+ else if (undosys == UNDOSYSTEM_SCULPT) {
+ name = ED_undo_paint_get_name(C, UNDO_PAINT_MESH, i, &active);
+ }
else {
name = BKE_undo_get_name(i, &active);
}
@@ -576,6 +584,9 @@ static int undo_history_exec(bContext *C, wmOperator *op)
else if (undosys == UNDOSYSTEM_IMAPAINT) {
ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item);
}
+ else if (undosys == UNDOSYSTEM_SCULPT) {
+ ED_undo_paint_step_num(C, UNDO_PAINT_MESH, item);
+ }
else {
ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
BKE_undo_number(C, item);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 1071e0f12e8..193b006cf0d 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4302,7 +4302,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
/* border/circle selection */
kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "pinned", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "pinned", true);
WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 20a8ab5c98c..59442e89787 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -46,6 +46,8 @@
#include "BLI_math_vector.h"
#include "BLI_string.h"
+#include "BLT_translation.h"
+
#include "BIF_gl.h"
#include "BKE_context.h"
@@ -54,6 +56,8 @@
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_uvedit.h"
#include "ED_screen.h"
@@ -259,25 +263,24 @@ static void stitch_preview_delete(StitchPreviewer *stitch_preview)
}
}
-#define HEADER_LENGTH 256
-
/* This function updates the header of the UV editor when the stitch tool updates its settings */
static void stitch_update_header(StitchState *state, bContext *C)
{
- static char str[] =
+ const char *str = IFACE_(
"Mode(TAB) %s, "
"(S)nap %s, "
"(M)idpoints %s, "
"(L)imit %.2f (Alt Wheel adjust) %s, "
"Switch (I)sland, "
- "shift select vertices";
+ "shift select vertices"
+ );
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- BLI_snprintf(msg, HEADER_LENGTH, str,
- state->mode == STITCH_VERT ? "Vertex" : "Edge",
+ BLI_snprintf(msg, sizeof(msg), str,
+ state->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
WM_bool_as_string(state->snap_islands),
WM_bool_as_string(state->midpoints),
state->limit_dist,
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 768624b1968..8e4ba4c0afa 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -49,6 +49,8 @@
#include "BLI_uvproject.h"
#include "BLI_string.h"
+#include "BLT_translation.h"
+
#include "BKE_cdderivedmesh.h"
#include "BKE_subsurf.h"
#include "BKE_context.h"
@@ -62,6 +64,8 @@
#include "PIL_time.h"
+#include "UI_interface.h"
+
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -554,12 +558,13 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
RNA_int_set(op->ptr, "iterations", ms->i);
if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
- char str[100];
+ char str[UI_MAX_DRAW_STR];
param_flush(ms->handle);
if (sa) {
- BLI_snprintf(str, sizeof(str), "Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)", ms->blend);
+ BLI_snprintf(str, sizeof(str),
+ IFACE_("Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)"), ms->blend);
ED_area_headerprint(sa, str);
}
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 136fec3dd1c..beb85798223 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -864,10 +864,10 @@ bool Controller::getComputeSteerableViewMapFlag() const
return _ComputeSteerableViewMap;
}
-void Controller::DrawStrokes()
+int Controller::DrawStrokes()
{
if (_ViewMap == 0)
- return;
+ return 0;
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "\n=== Stroke drawing ===" << endl;
@@ -875,12 +875,14 @@ void Controller::DrawStrokes()
_Chrono.start();
_Canvas->Draw();
real d = _Chrono.stop();
+ int strokeCount = _Canvas->getStrokeCount();
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Strokes generation : " << d << endl;
- cout << "Stroke count : " << _Canvas->getStrokeCount() << endl;
+ cout << "Stroke count : " << strokeCount << endl;
}
resetModified();
DeleteViewMap();
+ return strokeCount;
}
void Controller::ResetRenderCount()
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 6f3cb3b274b..154edaf1e53 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -75,7 +75,7 @@ public:
void ComputeSteerableViewMap();
void saveSteerableViewMapImages();
void toggleEdgeTesselationNature(Nature::EdgeNature iNature);
- void DrawStrokes();
+ int DrawStrokes();
void ResetRenderCount();
Render *RenderStrokes(Render *re, bool render);
void SwapStyleModules(unsigned i1, unsigned i2);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index dc88f69c95b..4d8c6a66d42 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -628,15 +628,19 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
re->stats_draw(re->sdh, &re->i);
re->i.infostr = NULL;
g_freestyle.scene = re->scene;
- controller->DrawStrokes();
- freestyle_render = controller->RenderStrokes(re, true);
+ int strokeCount = controller->DrawStrokes();
+ if (strokeCount > 0) {
+ freestyle_render = controller->RenderStrokes(re, true);
+ }
controller->CloseFile();
g_freestyle.scene = NULL;
// composite result
- FRS_composite_result(re, srl, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
+ if (freestyle_render) {
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
}
}
diff --git a/source/blender/freestyle/intern/system/PseudoNoise.cpp b/source/blender/freestyle/intern/system/PseudoNoise.cpp
index 4949cb8c430..638eb6ca16a 100644
--- a/source/blender/freestyle/intern/system/PseudoNoise.cpp
+++ b/source/blender/freestyle/intern/system/PseudoNoise.cpp
@@ -33,7 +33,7 @@
static int modf_to_index(Freestyle::real x, unsigned int range)
{
- if (finite(x)) {
+ if (isfinite(x)) {
Freestyle::real tmp;
int i = abs((int)(modf(x, &tmp) * range));
BLI_assert(i >= 0 && i < range);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 7cd05eff64e..94d52c3617c 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1496,7 +1496,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
function = gpu_lookup_function(name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
- return 0;
+ return false;
}
node = GPU_node_begin(name);
@@ -1516,7 +1516,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
gpu_material_add_node(mat, node);
- return 1;
+ return true;
}
bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...)
@@ -1530,7 +1530,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
function = gpu_lookup_function(name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
- return 0;
+ return false;
}
node = GPU_node_begin(name);
@@ -1577,7 +1577,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
gpu_material_add_node(mat, node);
- return 1;
+ return true;
}
int GPU_link_changed(GPUNodeLink *link)
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 7534d9d0fb9..c2a2b1804ca 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -871,14 +871,15 @@ bool GPU_fx_do_composite_pass(
float scale = scene->unit.system ? scene->unit.scale_length : 1.0f;
/* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
* unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
- * because the shader reads coordinates in world space, which is in blender units. */
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
float scale_camera = 0.001f / scale;
/* we want radius here for the aperture number */
float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop;
dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length /
- ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length));
- dof_params[1] = fx_dof->focus_distance / scale;
+ (fx_dof->focus_distance - scale_camera * fx_dof->focal_length));
+ dof_params[1] = fx_dof->focus_distance;
dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
dof_params[3] = fx_dof->num_blades;
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 1c22c89abf9..e5d51772bb2 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -509,6 +509,58 @@ static void gpu_verify_reflection(Image *ima)
}
}
+typedef struct VerifyThreadData {
+ ImBuf *ibuf;
+ float *srgb_frect;
+} VerifyThreadData;
+
+static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
+ ImBuf *ibuf,
+ const int start_line,
+ const int height)
+{
+ size_t offset = ibuf->channels * start_line * ibuf->x;
+ float *current_srgb_frect = srgb_frect + offset;
+ float *current_rect_float = ibuf->rect_float + offset;
+ IMB_buffer_float_from_float(current_srgb_frect,
+ current_rect_float,
+ ibuf->channels,
+ IB_PROFILE_SRGB,
+ IB_PROFILE_LINEAR_RGB, true,
+ ibuf->x, height,
+ ibuf->x, ibuf->x);
+ IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
+ /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */
+ IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height);
+}
+
+static void verify_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ VerifyThreadData *data = (VerifyThreadData *)data_v;
+ gpu_verify_high_bit_srgb_buffer_slice(data->srgb_frect,
+ data->ibuf,
+ start_scanline,
+ num_scanlines);
+}
+
+static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
+ ImBuf *ibuf)
+{
+ if (ibuf->y < 64) {
+ gpu_verify_high_bit_srgb_buffer_slice(srgb_frect,
+ ibuf,
+ 0, ibuf->y);
+ }
+ else {
+ VerifyThreadData data;
+ data.ibuf = ibuf;
+ data.srgb_frect = srgb_frect;
+ IMB_processor_apply_threaded_scanlines(ibuf->y, verify_thread_do, &data);
+ }
+}
+
int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data)
{
unsigned int *bind = NULL;
@@ -575,17 +627,18 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bo
* a high precision format only if it is available */
use_high_bit_depth = true;
}
+ else if (ibuf->rect == NULL) {
+ IMB_rect_from_float(ibuf);
+ }
/* we may skip this in high precision, but if not, we need to have a valid buffer here */
else if (ibuf->userflags & IB_RECT_INVALID) {
IMB_rect_from_float(ibuf);
}
/* TODO unneeded when float images are correctly treated as linear always */
- if (!is_data)
+ if (!is_data) {
do_color_management = true;
-
- if (ibuf->rect == NULL)
- IMB_rect_from_float(ibuf);
+ }
}
/* currently, tpage refresh is used by ima sequences */
@@ -622,12 +675,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bo
if (use_high_bit_depth) {
if (do_color_management) {
srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
- IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
- ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
- ibuf->x, ibuf->y, ibuf->x, ibuf->x);
- IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
- /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
- IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
+ gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
frect = srgb_frect + texwinsy * ibuf->x + texwinsx;
}
else {
@@ -650,13 +698,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bo
if (use_high_bit_depth) {
if (do_color_management) {
frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
- IMB_buffer_float_from_float(
- srgb_frect, ibuf->rect_float,
- ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
- ibuf->x, ibuf->y, ibuf->x, ibuf->x);
- IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
- /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
- IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
+ gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
}
else
frect = ibuf->rect_float;
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 7d433a78411..3c96b628cd6 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -259,8 +259,8 @@ bool GPU_legacy_support(void)
if (G.debug & G_DEBUG_GPU) {
printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile,
- profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT ? "compatibility" :
- profile & GL_CONTEXT_CORE_PROFILE_BIT ? "core" : "unknown");
+ (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" :
+ (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown");
}
if (profile == 0) {
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 18468c1674f..72a59e6843d 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -135,6 +135,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
col_to.a = col_from.a;
}
+void color_to_normal(vec3 color, out vec3 normal)
+{
+ normal.x = 2.0 * ((color.r) - 0.5);
+ normal.y = -2.0 * ((color.g) - 0.5);
+ normal.z = 2.0 * ((color.b) - 0.5);
+}
+
#define M_PI 3.14159265358979323846
#define M_1_PI 0.31830988618379069
@@ -369,6 +376,10 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
outval = length(outvec);
outvec = normalize(outvec);
}
+void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
+{
+ outvec = strength*v1 + (1 - strength) * v2;
+}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
@@ -2701,9 +2712,12 @@ void node_object_info(out vec3 location, out float object_index, out float mater
random = 0.0;
}
-void node_normal_map(float strength, vec4 color, vec3 N, out vec3 result)
+void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
{
- result = N;
+ vec3 B = tangent.w * cross(normal, tangent.xyz);
+
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+ outnormal = normalize(outnormal);
}
void node_bump(float strength, float dist, float height, vec3 N, out vec3 result)
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index ab822f1cd55..52febe642a0 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -163,6 +163,16 @@ void IMB_partial_display_buffer_update(struct ImBuf *ibuf, const float *linear_b
int xmin, int ymin, int xmax, int ymax,
bool copy_display_to_byte_buffer);
+void IMB_partial_display_buffer_update_threaded(struct ImBuf *ibuf,
+ const float *linear_buffer,
+ const unsigned char *buffer_byte,
+ int stride,
+ int offset_x, int offset_y,
+ const struct ColorManagedViewSettings *view_settings,
+ const struct ColorManagedDisplaySettings *display_settings,
+ int xmin, int ymin, int xmax, int ymax,
+ bool copy_display_to_byte_buffer);
+
void IMB_partial_display_buffer_update_delayed(struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax);
/* ** Pixel processor functions ** */
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 043f1602a76..93d2b3e0cd0 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -130,7 +130,18 @@ void IMB_freeImBuf(struct ImBuf *ibuf);
* \attention Defined in allocimbuf.c
*/
struct ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y,
- unsigned char d, unsigned int flags);
+ unsigned char planes, unsigned int flags);
+
+/**
+ * Initialize given ImBuf.
+ *
+ * Use in cases when temporary image buffer is allocated on stack.
+ *
+ * \attention Defined in allocimbuf.c
+ */
+bool IMB_initImBuf(struct ImBuf *ibuf,
+ unsigned int x, unsigned int y,
+ unsigned char planes, unsigned int flags);
/**
* Create a copy of a pixel buffer and wrap it to a new ImBuf
@@ -213,6 +224,10 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max,
int destx, int desty, int origx, int origy, int srcx, int srcy,
int width, int height, IMB_BlendMode mode, bool accumulate);
+void IMB_rectblend_threaded(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
+ unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max,
+ int destx, int desty, int origx, int origy, int srcx, int srcy,
+ int width, int height, IMB_BlendMode mode, bool accumulate);
/**
*
@@ -439,6 +454,9 @@ void IMB_buffer_float_from_byte(float *rect_to, const unsigned char *rect_from,
void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
int channels_from, int profile_to, int profile_from, bool predivide,
int width, int height, int stride_to, int stride_from);
+void IMB_buffer_float_from_float_threaded(float *rect_to, const float *rect_from,
+ int channels_from, int profile_to, int profile_from, bool predivide,
+ int width, int height, int stride_to, int stride_from);
void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from,
int channels_from, int width, int height, int stride_to, int stride_from, char *mask);
void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect_from,
@@ -580,6 +598,14 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void *customdata),
void *(do_thread) (void *));
+typedef void (*ScanlineThreadFunc) (void *custom_data,
+ int start_scanline,
+ int num_scanlines);
+void IMB_processor_apply_threaded_scanlines(int total_scanlines,
+ ScanlineThreadFunc do_thread,
+ void *custom_data);
+
+
/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 988f43ff9fa..ef3743d9c8a 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -446,49 +446,60 @@ ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, uchar planes, unsigned int
{
ImBuf *ibuf;
- ibuf = MEM_callocN(sizeof(ImBuf), "ImBuf_struct");
+ ibuf = MEM_mallocN(sizeof(ImBuf), "ImBuf_struct");
if (ibuf) {
- ibuf->x = x;
- ibuf->y = y;
- ibuf->planes = planes;
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15; /* the 15 means, set compression to low ratio but not time consuming */
- ibuf->channels = 4; /* float option, is set to other values when buffers get assigned */
- ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */
-
- if (flags & IB_rect) {
- if (imb_addrectImBuf(ibuf) == false) {
- IMB_freeImBuf(ibuf);
- return NULL;
- }
+ if (!IMB_initImBuf(ibuf, x, y, planes, flags)) {
+ IMB_freeImBuf(ibuf);
+ return NULL;
}
-
- if (flags & IB_rectfloat) {
- if (imb_addrectfloatImBuf(ibuf) == false) {
- IMB_freeImBuf(ibuf);
- return NULL;
- }
+ }
+
+ return (ibuf);
+}
+
+bool IMB_initImBuf(struct ImBuf *ibuf,
+ unsigned int x, unsigned int y,
+ unsigned char planes, unsigned int flags)
+{
+ memset(ibuf, 0, sizeof(ImBuf));
+
+ ibuf->x = x;
+ ibuf->y = y;
+ ibuf->planes = planes;
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15; /* the 15 means, set compression to low ratio but not time consuming */
+ ibuf->channels = 4; /* float option, is set to other values when buffers get assigned */
+ ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */
+
+ if (flags & IB_rect) {
+ if (imb_addrectImBuf(ibuf) == false) {
+ return false;
}
-
- if (flags & IB_zbuf) {
- if (addzbufImBuf(ibuf) == false) {
- IMB_freeImBuf(ibuf);
- return NULL;
- }
+ }
+
+ if (flags & IB_rectfloat) {
+ if (imb_addrectfloatImBuf(ibuf) == false) {
+ return false;
}
-
- if (flags & IB_zbuffloat) {
- if (addzbuffloatImBuf(ibuf) == false) {
- IMB_freeImBuf(ibuf);
- return NULL;
- }
+ }
+
+ if (flags & IB_zbuf) {
+ if (addzbufImBuf(ibuf) == false) {
+ return false;
}
+ }
- /* assign default spaces */
- colormanage_imbuf_set_default_spaces(ibuf);
+ if (flags & IB_zbuffloat) {
+ if (addzbuffloatImBuf(ibuf) == false) {
+ return false;
+ }
}
- return (ibuf);
+
+ /* assign default spaces */
+ colormanage_imbuf_set_default_spaces(ibuf);
+
+ return true;
}
/* does no zbuffers? */
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 562bdecb842..8b4e95ac452 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -184,8 +184,8 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
}
else {
if (verbose) {
- printf("DPX: Bad magic number %lu in \"%s\".\n",
- (uintptr_t)header.fileHeader.magic_num, byteStuff);
+ printf("DPX: Bad magic number %u in \"%s\".\n",
+ header.fileHeader.magic_num, byteStuff);
}
logImageClose(dpx);
return NULL;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index e4e93d3c4da..41812872f11 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -2027,11 +2027,18 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) {
if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
- IMB_partial_display_buffer_update(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect,
- ibuf->x, 0, 0, applied_view_settings, display_settings,
- ibuf->invalid_rect.xmin, ibuf->invalid_rect.ymin,
- ibuf->invalid_rect.xmax, ibuf->invalid_rect.ymax,
- false);
+ IMB_partial_display_buffer_update_threaded(ibuf,
+ ibuf->rect_float,
+ (unsigned char *) ibuf->rect,
+ ibuf->x,
+ 0, 0,
+ applied_view_settings,
+ display_settings,
+ ibuf->invalid_rect.xmin,
+ ibuf->invalid_rect.ymin,
+ ibuf->invalid_rect.xmax,
+ ibuf->invalid_rect.ymax,
+ false);
}
BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0);
@@ -2609,10 +2616,16 @@ void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *tot
* the rest buffers would be marked as dirty
*/
-static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffer, const float *linear_buffer,
- const unsigned char *byte_buffer, int display_stride, int linear_stride,
- int linear_offset_x, int linear_offset_y, ColormanageProcessor *cm_processor,
- const int xmin, const int ymin, const int xmax, const int ymax)
+static void partial_buffer_update_rect(ImBuf *ibuf,
+ unsigned char *display_buffer,
+ const float *linear_buffer,
+ const unsigned char *byte_buffer,
+ int display_stride,
+ int linear_stride,
+ int linear_offset_x, int linear_offset_y,
+ ColormanageProcessor *cm_processor,
+ const int xmin, const int ymin,
+ const int xmax, const int ymax)
{
int x, y;
int channels = ibuf->channels;
@@ -2731,12 +2744,50 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
}
-void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer,
- int stride, int offset_x, int offset_y,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- int xmin, int ymin, int xmax, int ymax,
- bool copy_display_to_byte_buffer)
+typedef struct PartialThreadData {
+ ImBuf *ibuf;
+ unsigned char *display_buffer;
+ const float *linear_buffer;
+ const unsigned char *byte_buffer;
+ int display_stride;
+ int linear_stride;
+ int linear_offset_x, linear_offset_y;
+ ColormanageProcessor *cm_processor;
+ int xmin, ymin, xmax;
+} PartialThreadData;
+
+static void partial_buffer_update_rect_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ PartialThreadData *data = (PartialThreadData *)data_v;
+ int ymin = data->ymin + start_scanline;
+ partial_buffer_update_rect(data->ibuf,
+ data->display_buffer,
+ data->linear_buffer,
+ data->byte_buffer,
+ data->display_stride,
+ data->linear_stride,
+ data->linear_offset_x,
+ data->linear_offset_y,
+ data->cm_processor,
+ data->xmin,
+ ymin,
+ data->xmax,
+ ymin + num_scanlines);
+}
+
+static void imb_partial_display_buffer_update_ex(ImBuf *ibuf,
+ const float *linear_buffer,
+ const unsigned char *byte_buffer,
+ int stride,
+ int offset_x, int offset_y,
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ int xmin, int ymin,
+ int xmax, int ymax,
+ bool copy_display_to_byte_buffer,
+ bool do_threads)
{
ColormanageCacheViewSettings cache_view_settings;
ColormanageCacheDisplaySettings cache_display_settings;
@@ -2755,16 +2806,20 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
BLI_lock_thread(LOCK_COLORMANAGE);
- if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0)
- display_buffer = colormanage_cache_get(ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
+ if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
+ display_buffer = colormanage_cache_get(ibuf,
+ &cache_view_settings,
+ &cache_display_settings,
+ &cache_handle);
+ }
- /* in some rare cases buffer's dimension could be changing directly from
+ /* In some rare cases buffer's dimension could be changing directly from
* different thread
* this i.e. happens when image editor acquires render result
*/
buffer_width = ibuf->x;
- /* mark all other buffers as invalid */
+ /* Mark all other buffers as invalid. */
memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
ibuf->display_buffer_flags[display_index] |= view_flag;
@@ -2789,15 +2844,42 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
* it first and byte buffer is likely to be out of date here.
*/
if (linear_buffer == NULL && byte_buffer != NULL) {
- skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
+ skip_transform = is_ibuf_rect_in_display_space(ibuf,
+ view_settings,
+ display_settings);
}
if (!skip_transform) {
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+ cm_processor = IMB_colormanagement_display_processor_new(
+ view_settings, display_settings);
}
- partial_buffer_update_rect(ibuf, display_buffer, linear_buffer, byte_buffer, buffer_width, stride,
- offset_x, offset_y, cm_processor, xmin, ymin, xmax, ymax);
+ if (do_threads) {
+ PartialThreadData data;
+ data.ibuf = ibuf;
+ data.display_buffer = display_buffer;
+ data.linear_buffer = linear_buffer;
+ data.byte_buffer = byte_buffer;
+ data.display_stride = buffer_width;
+ data.linear_stride = stride;
+ data.linear_offset_x = offset_x;
+ data.linear_offset_y = offset_y;
+ data.cm_processor = cm_processor;
+ data.xmin = xmin;
+ data.ymin = ymin;
+ data.xmax = xmax;
+ IMB_processor_apply_threaded_scanlines(
+ ymax - ymin, partial_buffer_update_rect_thread_do, &data);
+ }
+ else {
+ partial_buffer_update_rect(ibuf,
+ display_buffer, linear_buffer, byte_buffer,
+ buffer_width,
+ stride,
+ offset_x, offset_y,
+ cm_processor,
+ xmin, ymin, xmax, ymax);
+ }
if (cm_processor) {
IMB_colormanagement_processor_free(cm_processor);
@@ -2810,11 +2892,64 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
int y;
for (y = ymin; y < ymax; y++) {
size_t index = (size_t)y * buffer_width * 4;
- memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4);
+ memcpy((unsigned char *)ibuf->rect + index,
+ display_buffer + index,
+ (size_t)(xmax - xmin) * 4);
}
}
}
+void IMB_partial_display_buffer_update(ImBuf *ibuf,
+ const float *linear_buffer,
+ const unsigned char *byte_buffer,
+ int stride,
+ int offset_x, int offset_y,
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ int xmin, int ymin,
+ int xmax, int ymax,
+ bool copy_display_to_byte_buffer)
+{
+ imb_partial_display_buffer_update_ex(ibuf,
+ linear_buffer,
+ byte_buffer,
+ stride,
+ offset_x, offset_y,
+ view_settings,
+ display_settings,
+ xmin, ymin,
+ xmax, ymax,
+ copy_display_to_byte_buffer,
+ false);
+
+}
+
+void IMB_partial_display_buffer_update_threaded(struct ImBuf *ibuf,
+ const float *linear_buffer,
+ const unsigned char *byte_buffer,
+ int stride,
+ int offset_x, int offset_y,
+ const struct ColorManagedViewSettings *view_settings,
+ const struct ColorManagedDisplaySettings *display_settings,
+ int xmin, int ymin, int xmax, int ymax,
+ bool copy_display_to_byte_buffer)
+{
+ int width = xmax - xmin;
+ int height = ymax - ymin;
+ bool do_threads = (((size_t)width) * height >= 64 * 64);
+ imb_partial_display_buffer_update_ex(ibuf,
+ linear_buffer,
+ byte_buffer,
+ stride,
+ offset_x, offset_y,
+ view_settings,
+ display_settings,
+ xmin, ymin,
+ xmax, ymax,
+ copy_display_to_byte_buffer,
+ do_threads);
+}
+
void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
{
if (ibuf->invalid_rect.xmin == ibuf->invalid_rect.xmax) {
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 455b78bce4d..62fd623ecfa 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -532,6 +532,76 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
}
}
+typedef struct FloatToFloatThreadData {
+ float *rect_to;
+ const float *rect_from;
+ int channels_from;
+ int profile_to;
+ int profile_from;
+ bool predivide;
+ int width;
+ int stride_to;
+ int stride_from;
+} FloatToFloatThreadData;
+
+static void imb_buffer_float_from_float_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FloatToFloatThreadData *data = (FloatToFloatThreadData *)data_v;
+ size_t offset_from = ((size_t)start_scanline) * data->stride_from * data->channels_from;
+ size_t offset_to = ((size_t)start_scanline) * data->stride_to * data->channels_from;
+ IMB_buffer_float_from_float(data->rect_to + offset_to,
+ data->rect_from + offset_from,
+ data->channels_from,
+ data->profile_to,
+ data->profile_from,
+ data->predivide,
+ data->width,
+ num_scanlines,
+ data->stride_to,
+ data->stride_from);
+}
+
+void IMB_buffer_float_from_float_threaded(float *rect_to,
+ const float *rect_from,
+ int channels_from,
+ int profile_to,
+ int profile_from,
+ bool predivide,
+ int width,
+ int height,
+ int stride_to,
+ int stride_from)
+{
+ if (((size_t)width) * height < 64 * 64) {
+ IMB_buffer_float_from_float(rect_to,
+ rect_from,
+ channels_from,
+ profile_to,
+ profile_from,
+ predivide,
+ width,
+ height,
+ stride_to,
+ stride_from);
+ }
+ else {
+ FloatToFloatThreadData data;
+ data.rect_to = rect_to;
+ data.rect_from = rect_from;
+ data.channels_from = channels_from;
+ data.profile_to = profile_to;
+ data.profile_from = profile_from;
+ data.predivide = predivide;
+ data.width = width;
+ data.stride_to = stride_to;
+ data.stride_from = stride_from;
+ IMB_processor_apply_threaded_scanlines(
+ height, imb_buffer_float_from_float_thread_do, &data);
+ }
+}
+
/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, int channels_from,
int width, int height, int stride_to, int stride_from, char *mask)
@@ -674,25 +744,24 @@ void IMB_rect_from_float(ImBuf *ibuf)
ibuf->userflags &= ~IB_RECT_INVALID;
}
-/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
-void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data)
-{
- const float *rect_float;
+typedef struct PartialThreadData {
+ ImBuf *ibuf;
+ float *buffer;
uchar *rect_byte;
- int profile_from = IB_PROFILE_LINEAR_RGB;
-
- /* verify we have a float buffer */
- if (ibuf->rect_float == NULL || buffer == NULL)
- return;
-
- /* create byte rect if it didn't exist yet */
- if (ibuf->rect == NULL)
- imb_addrectImBuf(ibuf);
-
- /* do conversion */
- rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
- rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
-
+ const float *rect_float;
+ int width;
+ bool is_data;
+} PartialThreadData;
+
+static void partial_rect_from_float_slice(float *buffer,
+ uchar *rect_byte,
+ ImBuf *ibuf,
+ const float *rect_float,
+ const int w,
+ const int h,
+ const bool is_data)
+{
+ const int profile_from = IB_PROFILE_LINEAR_RGB;
if (is_data) {
/* exception for non-color data, just copy float */
IMB_buffer_float_from_float(buffer, rect_float,
@@ -715,6 +784,58 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0,
w, h, ibuf->x, w);
}
+}
+
+static void partial_rect_from_float_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ PartialThreadData *data = (PartialThreadData *)data_v;
+ ImBuf *ibuf = data->ibuf;
+ size_t global_offset = ((size_t)ibuf->x) * start_scanline;
+ size_t local_offset = ((size_t)data->width) * start_scanline;
+ partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels,
+ data->rect_byte + global_offset * 4,
+ ibuf,
+ data->rect_float + global_offset * ibuf->channels,
+ data->width,
+ num_scanlines,
+ data->is_data);
+}
+
+/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
+void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data)
+{
+ const float *rect_float;
+ uchar *rect_byte;
+
+ /* verify we have a float buffer */
+ if (ibuf->rect_float == NULL || buffer == NULL)
+ return;
+
+ /* create byte rect if it didn't exist yet */
+ if (ibuf->rect == NULL)
+ imb_addrectImBuf(ibuf);
+
+ /* do conversion */
+ rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
+ rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
+
+ if (((size_t)w) * h < 64 * 64) {
+ partial_rect_from_float_slice(
+ buffer, rect_byte, ibuf, rect_float, w, h, is_data);
+ }
+ else {
+ PartialThreadData data;
+ data.ibuf = ibuf;
+ data.buffer = buffer;
+ data.rect_byte = rect_byte;
+ data.rect_float = rect_float;
+ data.width = w;
+ data.is_data = is_data;
+ IMB_processor_apply_threaded_scanlines(
+ h, partial_rect_from_float_thread_do, &data);
+ }
/* ensure user flag is reset */
ibuf->userflags &= ~IB_RECT_INVALID;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 9e4bb957f66..0f5fd6518fb 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -374,6 +374,60 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
BLI_task_pool_free(task_pool);
}
+typedef struct ScanlineGlobalData {
+ void *custom_data;
+ ScanlineThreadFunc do_thread;
+ int scanlines_per_task;
+ int total_scanlines;
+} ScanlineGlobalData;
+
+typedef struct ScanlineTask {
+ int start_scanline;
+ int num_scanlines;
+} ScanlineTask;
+
+static void processor_apply_scanline_func(TaskPool * __restrict pool,
+ void *taskdata,
+ int UNUSED(threadid))
+{
+ ScanlineGlobalData *data = BLI_task_pool_userdata(pool);
+ int start_scanline = GET_INT_FROM_POINTER(taskdata);
+ int num_scanlines = min_ii(data->scanlines_per_task,
+ data->total_scanlines - start_scanline);
+ data->do_thread(data->custom_data,
+ start_scanline,
+ num_scanlines);
+}
+
+void IMB_processor_apply_threaded_scanlines(int total_scanlines,
+ ScanlineThreadFunc do_thread,
+ void *custom_data)
+{
+ const int scanlines_per_task = 64;
+ ScanlineGlobalData data;
+ data.custom_data = custom_data;
+ data.do_thread = do_thread;
+ data.scanlines_per_task = scanlines_per_task;
+ data.total_scanlines = total_scanlines;
+ const int total_tasks = (total_scanlines + scanlines_per_task - 1) / scanlines_per_task;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &data);
+ for (int i = 0, start_line = 0; i < total_tasks; i++) {
+ BLI_task_pool_push(task_pool,
+ processor_apply_scanline_func,
+ SET_INT_IN_POINTER(start_line),
+ false,
+ TASK_PRIORITY_LOW);
+ start_line += scanlines_per_task;
+ }
+
+ /* work and wait until tasks are done */
+ BLI_task_pool_work_and_wait(task_pool);
+
+ /* Free memory. */
+ BLI_task_pool_free(task_pool);
+}
+
/* Alpha-under */
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 570ca5ba06e..390f2502ee7 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -63,12 +63,12 @@ enum {
DCP_CINEMA4K = 4,
};
-static int check_jp2(const unsigned char *mem) /* J2K_CFMT */
+static bool check_jp2(const unsigned char *mem) /* J2K_CFMT */
{
return memcmp(JP2_HEAD, mem, sizeof(JP2_HEAD)) ? 0 : 1;
}
-static int check_j2k(const unsigned char *mem) /* J2K_CFMT */
+static bool check_j2k(const unsigned char *mem) /* J2K_CFMT */
{
return memcmp(J2K_HEAD, mem, sizeof(J2K_HEAD)) ? 0 : 1;
}
@@ -133,7 +133,7 @@ struct ImBuf *imb_jp2_decode(const unsigned char *mem, size_t size, int flags, c
unsigned int i, i_next, w, h, planes;
unsigned int y;
int *r, *g, *b, *a; /* matching 'opj_image_comp.data' type */
- int is_jp2, is_j2k;
+ bool is_jp2, is_j2k;
opj_dparameters_t parameters; /* decompression parameters */
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 47fa4c1de0c..fdadb783815 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -38,6 +38,32 @@
#include <set>
#include <errno.h>
#include <algorithm>
+#include <iostream>
+
+#include <half.h>
+#include <Iex.h>
+#include <ImfVersion.h>
+#include <ImathBox.h>
+#include <ImfArray.h>
+#include <ImfIO.h>
+#include <ImfChannelList.h>
+#include <ImfPixelType.h>
+#include <ImfInputFile.h>
+#include <ImfOutputFile.h>
+#include <ImfCompression.h>
+#include <ImfCompressionAttribute.h>
+#include <ImfStringAttribute.h>
+#include <ImfStandardAttributes.h>
+
+/* multiview/multipart */
+#include <ImfMultiView.h>
+#include <ImfMultiPartInputFile.h>
+#include <ImfInputPart.h>
+#include <ImfOutputPart.h>
+#include <ImfMultiPartOutputFile.h>
+#include <ImfTiledOutputPart.h>
+#include <ImfPartType.h>
+#include <ImfPartHelper.h>
#include "DNA_scene_types.h" /* For OpenEXR compression constants */
@@ -74,33 +100,6 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "openexr_multi.h"
}
-#include <iostream>
-
-#include <half.h>
-#include <Iex.h>
-#include <ImfVersion.h>
-#include <ImathBox.h>
-#include <ImfArray.h>
-#include <ImfIO.h>
-#include <ImfChannelList.h>
-#include <ImfPixelType.h>
-#include <ImfInputFile.h>
-#include <ImfOutputFile.h>
-#include <ImfCompression.h>
-#include <ImfCompressionAttribute.h>
-#include <ImfStringAttribute.h>
-#include <ImfStandardAttributes.h>
-
-/* multiview/multipart */
-#include <ImfMultiView.h>
-#include <ImfMultiPartInputFile.h>
-#include <ImfInputPart.h>
-#include <ImfOutputPart.h>
-#include <ImfMultiPartOutputFile.h>
-#include <ImfTiledOutputPart.h>
-#include <ImfPartType.h>
-#include <ImfPartHelper.h>
-
extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index c7b347cb20c..3360fd7548e 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -693,6 +693,69 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
}
}
+typedef struct RectBlendThreadData {
+ ImBuf *dbuf, *obuf, *sbuf;
+ unsigned short *dmask, *curvemask, *texmask;
+ float mask_max;
+ int destx, desty, origx, origy;
+ int srcx, srcy, width;
+ IMB_BlendMode mode;
+ bool accumulate;
+} RectBlendThreadData;
+
+static void rectblend_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ RectBlendThreadData *data = (RectBlendThreadData *)data_v;
+ IMB_rectblend(data->dbuf, data->obuf, data->sbuf,
+ data->dmask, data->curvemask, data->texmask,
+ data->mask_max,
+ data->destx,
+ data->desty + start_scanline,
+ data->origx,
+ data->origy + start_scanline,
+ data->srcx,
+ data->srcy + start_scanline,
+ data->width, num_scanlines,
+ data->mode, data->accumulate);
+}
+
+void IMB_rectblend_threaded(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf,
+ unsigned short *dmask, unsigned short *curvemask,
+ unsigned short *texmask, float mask_max,
+ int destx, int desty, int origx, int origy,
+ int srcx, int srcy, int width, int height,
+ IMB_BlendMode mode, bool accumulate)
+{
+ if (((size_t)width) * height < 64 * 64) {
+ IMB_rectblend(dbuf, obuf, sbuf, dmask, curvemask, texmask,
+ mask_max, destx, desty, origx, origy,
+ srcx, srcy, width, height, mode, accumulate);
+ }
+ else {
+ RectBlendThreadData data;
+ data.dbuf = dbuf;
+ data.obuf = obuf;
+ data.sbuf = sbuf;
+ data.dmask = dmask;
+ data.curvemask = curvemask;
+ data.texmask = texmask;
+ data.mask_max = mask_max;
+ data.destx = destx;
+ data.desty = desty;
+ data.origx = origx;
+ data.origy = origy;
+ data.srcx = srcx;
+ data.srcy = srcy;
+ data.width = width;
+ data.mode = mode;
+ data.accumulate = accumulate;
+ IMB_processor_apply_threaded_scanlines(
+ height, rectblend_thread_do, &data);
+ }
+}
+
/* fill */
void IMB_rectfill(ImBuf *drect, const float col[4])
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 19edce3da3b..a55cef60943 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -719,6 +719,9 @@ ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *i
IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, ibuf_left->x, ibuf_left->y, &width, &height);
ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect));
+ ibuf_stereo->rect_colorspace = ibuf_left->rect_colorspace;
+ ibuf_stereo->float_colorspace = ibuf_left->float_colorspace;
+
/* copy flags for IB_fields and other settings */
ibuf_stereo->flags = ibuf_left->flags;
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 96d7ec3128c..4d82e4528d6 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -199,7 +199,8 @@ typedef struct bPoseChannel {
char constflag; /* for quick detecting which constraints affect this channel */
char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */
char drawflag;
- char pad0[5];
+ char bboneflag;
+ char pad0[4];
struct Bone *bone; /* set on read file or rebuild pose */
struct bPoseChannel *parent; /* set on read file or rebuild pose */
@@ -242,7 +243,16 @@ typedef struct bPoseChannel {
float ikstretch;
float ikrotweight; /* weight of joint rotation constraint */
float iklinweight; /* weight of joint stretch constraint */
-
+
+ /* curved bones settings - these are for animating, and are applied on top of the copies in pchan->bone */
+ float roll1, roll2;
+ float curveInX, curveInY;
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
+ struct bPoseChannel *bbone_prev; /* next/prev bones to use as handle references when calculating bbones (optional) */
+ struct bPoseChannel *bbone_next;
+
void *temp; /* use for outliner */
} bPoseChannel;
@@ -253,17 +263,17 @@ typedef enum ePchan_Flag {
POSE_LOC = (1 << 0),
POSE_ROT = (1 << 1),
POSE_SIZE = (1 << 2),
- /* old IK/cache stuff... */
-#if 0
- POSE_IK_MAT = (1 << 3),
- POSE_UNUSED2 = (1 << 4),
- POSE_UNUSED3 = (1 << 5),
- POSE_UNUSED4 = (1 << 6),
- POSE_UNUSED5 = (1 << 7),
- /* has Standard IK */
- POSE_HAS_IK = (1 << 8),
-#endif
- /* IK/Pose solving*/
+
+ /* old IK/cache stuff
+ * - used to be here from (1 << 3) to (1 << 8)
+ * but has been repurposed since 2.77.2
+ * as they haven't been used in over 10 years
+ */
+
+ /* has BBone deforms */
+ POSE_BBONE_SHAPE = (1 << 3),
+
+ /* IK/Pose solving */
POSE_CHAIN = (1 << 9),
POSE_DONE = (1 << 10),
/* visualization */
@@ -318,6 +328,16 @@ typedef enum ePchan_DrawFlag {
#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
(pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
+/* PoseChannel->bboneflag */
+typedef enum ePchan_BBoneFlag {
+ /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbours */
+ PCHAN_BBONE_CUSTOM_HANDLES = (1 << 1),
+ /* Evaluate start handle as being "relative" */
+ PCHAN_BBONE_CUSTOM_START_REL = (1 << 2),
+ /* Evaluate end handle as being "relative" */
+ PCHAN_BBONE_CUSTOM_END_REL = (1 << 3),
+} ePchan_BBoneFlag;
+
/* PoseChannel->rotmode and Object->rotmode */
typedef enum eRotationModes {
/* quaternion rotations (default, and for older Blender versions) */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index b995e6917a9..cda6441f0ae 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -68,11 +68,18 @@ typedef struct Bone {
float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */
float ease1, ease2; /* length of bezier handles */
float rad_head, rad_tail; /* radius for head/tail sphere, defining deform as well, parent->rad_tip overrides rad_head */
-
+
+ float roll1, roll2; /* curved bones settings - these define the "restpose" for a curved bone */
+ float curveInX, curveInY;
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
float size[3]; /* patch for upward compat, UNUSED! */
int layer; /* layers that bone appears on */
short segments; /* for B-bones */
- short pad[1];
+
+ short pad1;
+
} Bone;
typedef struct bArmature {
@@ -204,7 +211,8 @@ typedef enum eBone_Flag {
BONE_TRANSFORM_CHILD = (1 << 20), /* Indicates that a parent is also being transformed */
BONE_UNSELECTABLE = (1 << 21), /* bone cannot be selected */
BONE_NO_LOCAL_LOCATION = (1 << 22), /* bone location is in armature space */
- BONE_RELATIVE_PARENTING = (1 << 23) /* object child will use relative transform (like deform) */
+ BONE_RELATIVE_PARENTING = (1 << 23), /* object child will use relative transform (like deform) */
+ BONE_ADD_PARENT_END_ROLL = (1 << 24) /* it will add the parent end roll to the inroll */
} eBone_Flag;
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 7f2e1aaadf9..68741578f27 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -53,6 +53,10 @@ typedef struct CameraStereoSettings {
short pivot;
short flag;
short pad;
+ /* Cut-off angle at which interocular distance start to fade down. */
+ float pole_merge_angle_from;
+ /* Cut-off angle at which interocular distance stops to fade down. */
+ float pole_merge_angle_to;
} CameraStereoSettings;
typedef struct Camera {
@@ -152,6 +156,7 @@ enum {
/* stereo->flag */
enum {
CAM_S3D_SPHERICAL = (1 << 0),
+ CAM_S3D_POLE_MERGE = (1 << 1),
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 86991245068..5fcd374b21f 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -516,7 +516,9 @@ typedef enum eBConstraint_Flags {
/* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */
CONSTRAINT_PROXY_LOCAL = (1<<8),
/* indicates that constraint is temporarily disabled (only used in GE) */
- CONSTRAINT_OFF = (1<<9)
+ CONSTRAINT_OFF = (1<<9),
+ /* use bbone curve shape when calculating headtail values */
+ CONSTRAINT_BBONE_SHAPE = (1<<10),
} eBConstraint_Flags;
/* bConstraint->ownspace/tarspace */
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index fc7959c0043..b2ab0d2a08d 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -58,7 +58,7 @@ typedef struct FileGlobal {
/* minversion: in file, the oldest past blender version you can use compliant */
/* example: if in 2.43 the meshes lose mesh data, minversion is 2.43 then too */
/* or: in 2.42, subversion 1, same as above, minversion then is 2.42, min subversion 1 */
-/* (defines for version are in the BKE_blender.h file, for historic reasons) */
+/* (defines for version are in the BKE_blender_version.h file, for historic reasons) */
#endif
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index e5e193d479b..41f53f9f51c 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -57,6 +57,14 @@ typedef enum eGPDspoint_Flag {
GP_SPOINT_TAG = (1 << 1),
} eGPSPoint_Flag;
+/* Grease-Pencil Annotations - 'Triangle'
+ * -> A triangle contains the index of three vertices for filling the stroke
+ * This is only used if high quality fill is enabled
+ */
+typedef struct bGPDtriangle {
+ int v1, v2, v3; /* indices for tesselated triangle used for GP Fill */
+} bGPDtriangle;
+
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
@@ -69,6 +77,10 @@ typedef struct bGPDstroke {
short thickness; /* thickness of stroke (currently not used) */
short flag; /* various settings about this stroke */
+
+ bGPDtriangle *triangles;/* tesselated triangles for GP Fill */
+ int tot_triangles; /* number of triangles in array */
+ int pad1, *pad2;
double inittime; /* Init time of stroke */
} bGPDstroke;
@@ -83,6 +95,8 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_2DIMAGE = (1 << 2),
/* stroke is selected */
GP_STROKE_SELECT = (1 << 3),
+ /* Recalculate triangulation for high quality fill (when true, force a new recalc) */
+ GP_STROKE_RECALC_CACHES = (1 << 4),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
@@ -132,8 +146,9 @@ typedef struct bGPDlayer {
* this is used for the name of the layer too and kept unique. */
float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
+ short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
short sublevel; /* number of times to subdivide new strokes */
- short pad[5]; /* padding for compiler error */
+ short pad[4]; /* padding for compiler error */
} bGPDlayer;
/* bGPDlayer->flag */
@@ -160,6 +175,8 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_GHOST_NEXTCOL = (1 << 9),
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
GP_LAYER_VOLUMETRIC = (1 << 10),
+ /* Use high quality fill (instead of buggy legacy OpenGL Fill) */
+ GP_LAYER_HQ_FILL = (1 << 11)
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 8790f736600..0c500e366a7 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -197,6 +197,10 @@ typedef struct Material {
short tot_slots;
short pad4[3];
+ /* multiple tangent (Normal Map node) */
+ char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
+ int nmap_tangent_names_count, pad5;
+
struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
* with refresh_texpaint_image_cache */
ListBase gpumaterial; /* runtime */
@@ -305,6 +309,7 @@ typedef struct Material {
/* mode2 (is int) */
#define MA_CASTSHADOW (1 << 0)
#define MA_MODE2_PIPELINE (MA_CASTSHADOW)
+#define MA_TANGENT_CONCRETE (1 << 1)
/* mapflag */
#define MA_MAPFLAG_UVPROJECT (1 << 0)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index c75a019a28e..6cba3322135 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -689,6 +689,8 @@ typedef struct NodeColorBalance {
float slope[3];
float offset[3];
float power[3];
+ float offset_basis;
+ char _pad[4];
/* LGG parameters */
float lift[3];
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a8f78f6bb34..39508e17be5 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1266,6 +1266,41 @@ typedef enum {
UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE = (1 << 4)
} UnifiedPaintSettingsFlags;
+
+typedef struct CurvePaintSettings {
+ char curve_type;
+ char flag;
+ char depth_mode;
+ char surface_plane;
+ int error_threshold;
+ float radius_min, radius_max;
+ float radius_taper_start, radius_taper_end;
+ float surface_offset;
+ float corner_angle;
+} CurvePaintSettings;
+
+/* CurvePaintSettings.flag */
+enum {
+ CURVE_PAINT_FLAG_CORNERS_DETECT = (1 << 0),
+ CURVE_PAINT_FLAG_PRESSURE_RADIUS = (1 << 1),
+ CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS = (1 << 2),
+ CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS = (1 << 3),
+};
+
+/* CurvePaintSettings.depth_mode */
+enum {
+ CURVE_PAINT_PROJECT_CURSOR = 0,
+ CURVE_PAINT_PROJECT_SURFACE = 1,
+};
+
+/* CurvePaintSettings.surface_plane */
+enum {
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW = 0,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE = 1,
+ CURVE_PAINT_SURFACE_PLANE_VIEW = 2,
+};
+
+
/* *************************************************************** */
/* Stats */
@@ -1417,6 +1452,8 @@ typedef struct ToolSettings {
/* Unified Paint Settings */
struct UnifiedPaintSettings unified_paint_settings;
+ struct CurvePaintSettings curve_paint_settings;
+
struct MeshStatVis statvis;
} ToolSettings;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 3a64890a84b..1f4e4df4660 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -274,6 +274,7 @@ typedef struct GaussianBlurVars {
typedef struct TextVars {
char text[512];
int text_size;
+ float color[4], shadow_color[4];
float loc[2];
float wrap_width;
char flag;
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 651794da50d..fc94a8d9ff4 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -720,6 +720,28 @@ static int arraysize(const char *str)
return mul;
}
+static bool check_field_alignment(int firststruct, int structtype, int type, int len,
+ const char *name, const char *detail)
+{
+ bool result = true;
+ if (type < firststruct && typelens_native[type] > 4 && (len % 8)) {
+ fprintf(stderr, "Align 8 error (%s) in struct: %s %s (add %d padding bytes)\n",
+ detail, types[structtype], name, len % 8);
+ result = false;
+ }
+ if (typelens_native[type] > 3 && (len % 4) ) {
+ fprintf(stderr, "Align 4 error (%s) in struct: %s %s (add %d padding bytes)\n",
+ detail, types[structtype], name, len % 4);
+ result = false;
+ }
+ if (typelens_native[type] == 2 && (len % 2) ) {
+ fprintf(stderr, "Align 2 error (%s) in struct: %s %s (add %d padding bytes)\n",
+ detail, types[structtype], name, len % 2);
+ result = false;
+ }
+ return result;
+}
+
static int calculate_structlens(int firststruct)
{
int unknown = nr_structs, lastunknown;
@@ -815,20 +837,11 @@ static int calculate_structlens(int firststruct)
}
}
- /* 2-4-8 aligned/ */
- if (type < firststruct && typelens_native[type] > 4 && (len_native % 8)) {
- fprintf(stderr, "Align 8 error in struct: %s %s (add %d padding bytes)\n",
- types[structtype], cp, len_native % 8);
- dna_error = 1;
- }
- if (typelens_native[type] > 3 && (len_native % 4) ) {
- fprintf(stderr, "Align 4 error in struct: %s %s (add %d padding bytes)\n",
- types[structtype], cp, len_native % 4);
+ /* Check 2-4-8 aligned. */
+ if (!check_field_alignment(firststruct, structtype, type, len_32, cp, "32 bit")) {
dna_error = 1;
}
- else if (typelens_native[type] == 2 && (len_native % 2) ) {
- fprintf(stderr, "Align 2 error in struct: %s %s (add %d padding bytes)\n",
- types[structtype], cp, len_native % 2);
+ if (!check_field_alignment(firststruct, structtype, type, len_64, cp, "64 bit")) {
dna_error = 1;
}
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 04a2361b903..d8bea93bcbc 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -301,11 +301,25 @@ typedef struct RawArray {
int stride;
} RawArray;
+/**
+ * This struct is are typically defined in arrays which define an *enum* for RNA,
+ * which is used by the RNA API both for user-interface and the Python API.
+ */
typedef struct EnumPropertyItem {
+ /** The internal value of the enum, not exposed to users. */
int value;
+ /**
+ * Note that identifiers must be unique within the array,
+ * by convention they're upper case with underscores for separators.
+ * - An empty string is used to define menu separators.
+ * - NULL denotes the end of the array of items.
+ */
const char *identifier;
+ /** Optional icon, typically 'ICON_NONE' */
int icon;
+ /** Name displayed in the interface. */
const char *name;
+ /** Longer description used in the interface. */
const char *description;
} EnumPropertyItem;
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index b425a454d33..a09853eaddc 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -333,7 +333,7 @@ static void rna_Actuator_constraint_detect_material_set(struct PointerRNA *ptr,
bActuator *act = (bActuator *)ptr->data;
bConstraintActuator *ca = act->data;
- short old_value = (ca->flag & ACT_CONST_MATERIAL ? 1 : 0);
+ short old_value = (ca->flag & ACT_CONST_MATERIAL) ? 1 : 0;
if (old_value != value) {
ca->flag ^= ACT_CONST_MATERIAL;
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index a8ef4664fd7..842e220e8b5 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -482,6 +482,82 @@ static void rna_Armature_transform(struct bArmature *arm, float *mat)
#else
+/* Settings for curved bbone settings - The posemode values get applied over the top of the editmode ones */
+void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
+{
+#define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone) \
+ { \
+ if (is_posebone) \
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); \
+ else \
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data"); \
+ } (void)0;
+
+ PropertyRNA *prop;
+
+ /* Roll In/Out */
+ prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "roll1");
+ RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
+ RNA_def_property_ui_text(prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "roll2");
+ RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
+ RNA_def_property_ui_text(prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ if (is_posebone == false) {
+ prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Inherit End Roll", "Use Roll Out of parent bone as Roll In of its children");
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ADD_PARENT_END_ROLL);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+ }
+
+ /* Curve X/Y Offsets */
+ prop = RNA_def_property(srna, "bbone_curveinx", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveInX");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveInY");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveOutX");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveOutY");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ /* Scale In/Out */
+ prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scaleIn");
+ RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale In", "Scale factor for start of the B-Bone, adjusts thickness (for tapering effects)");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_scaleout", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scaleOut");
+ RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale Out", "Scale factor for end of the B-Bone, adjusts thickness (for tapering effects)");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+#undef RNA_DEF_CURVEBONE_UPDATE
+}
+
static void rna_def_bone_common(StructRNA *srna, int editbone)
{
PropertyRNA *prop;
@@ -653,6 +729,7 @@ static void rna_def_bone(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
+ rna_def_bone_curved_common(srna, 0);
/* XXX should we define this in PoseChannel wrapping code instead?
* But PoseChannels directly get some of their flags from here... */
@@ -766,6 +843,7 @@ static void rna_def_edit_bone(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
rna_def_bone_common(srna, 1);
+ rna_def_bone_curved_common(srna, 0);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index e3733ff2850..ac348c1750c 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -530,10 +530,12 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
switch ((BrushMaskTool)me->mask_tool) {
case BRUSH_MASK_DRAW:
return prop_direction_items;
- break;
+
case BRUSH_MASK_SMOOTH:
return prop_default_items;
- break;
+
+ default:
+ return prop_default_items;
}
case SCULPT_TOOL_FLATTEN:
@@ -554,7 +556,6 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
default:
return prop_default_items;
}
- break;
case ePaintTexture2D:
case ePaintTextureProjective:
@@ -565,7 +566,6 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
default:
return prop_default_items;
}
- break;
default:
return prop_default_items;
@@ -653,34 +653,34 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "tex_paint_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_tex_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "mask_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_mask_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RAKE);
RNA_def_property_ui_text(prop, "Rake", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RANDOM);
RNA_def_property_ui_text(prop, "Random", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "random_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI * 2);
RNA_def_property_ui_text(prop, "Random Angle", "Brush texture random angle");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
TEXTURE_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source");
TEXTURE_CAPABILITY(has_random_texture_angle, "Has Random Texture Angle");
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index d5044ec9838..dcb4d65f3f9 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -132,14 +132,14 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 2);
+ RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 3);
RNA_def_property_ui_text(prop, "Interocular Distance",
"Set the distance between the eyes - the stereo plane distance / 30 should be fine");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "convergence_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.00001f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.00001f, 15.f, 1, 2);
+ RNA_def_property_ui_range(prop, 0.00001f, 15.f, 1, 3);
RNA_def_property_ui_text(prop, "Convergence Plane Distance",
"The converge point for the stereo cameras "
"(often the distance between a projector and the projection screen)");
@@ -151,6 +151,24 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
"Render every pixel rotating the camera around the "
"middle of the interocular distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "use_pole_merge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_S3D_POLE_MERGE);
+ RNA_def_property_ui_text(prop, "Use Pole Merge",
+ "Fade interocular distance to 0 after the given cutoff angle");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pole_merge_angle_from", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0f);
+ RNA_def_property_ui_text(prop, "Pole Merge Start Angle",
+ "Angle at which interocular distance starts to fade to 0");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pole_merge_angle_to", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0f);
+ RNA_def_property_ui_text(prop, "Pole Merge End Angle",
+ "Angle at which interocular distance is 0");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
void RNA_def_camera(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index b75a3f0320b..c91b6487653 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -535,6 +535,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_SEW);
RNA_def_property_ui_text(prop, "Sew Cloth", "Pulls loose edges together");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "vertex_group_bending", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ClothSettings_bend_vgroup_get", "rna_ClothSettings_bend_vgroup_length",
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 0b5d0f3d41d..98560bf3452 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -483,6 +483,21 @@ static EnumPropertyItem constraint_distance_items[] = {
};
+static void rna_def_constraint_headtail_common(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
+ RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bbone_shape", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, "bConstraint", "flag", CONSTRAINT_BBONE_SHAPE);
+ RNA_def_property_ui_text(prop, "Follow B-Bone", "Follow shape of B-Bone segments when calculating Head/Tail position");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+}
+
static void rna_def_constrainttarget(BlenderRNA *brna)
{
StructRNA *srna;
@@ -787,10 +802,7 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TrackToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Track To Constraint", "Aim the constrained object toward the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTrackToConstraint", "data");
@@ -831,10 +843,7 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyLocationConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Location Constraint", "Copy the location of the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLocateLikeConstraint", "data");
@@ -1022,10 +1031,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Transforms Constraint", "Copy all the transforms of the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTransLikeConstraint", "data");
@@ -1200,10 +1206,7 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Locked Track Constraint",
"Point toward the target along the track axis, while locking the other axis");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLockTrackConstraint", "data");
@@ -1327,10 +1330,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "StretchToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Stretch To Constraint", "Stretch to meet the target object");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bStretchToConstraint", "data");
@@ -2122,10 +2122,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
srna = RNA_def_struct(brna, "LimitDistanceConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Limit Distance Constraint", "Limit the distance from target object");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDistLimitConstraint", "data");
@@ -2236,10 +2233,7 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Damped Track Constraint",
"Point toward target by taking the shortest rotation path");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDampTrackConstraint", "data");
@@ -2396,10 +2390,7 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
srna = RNA_def_struct(brna, "PivotConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Pivot Constraint", "Rotate around a different point");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bPivotConstraint", "data");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index b765ca10eec..1487dfa074e 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -61,7 +61,7 @@ EnumPropertyItem rna_enum_fmodifier_type_items[] = {
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise",
"Add pseudo-random noise on top of F-Curves"},
/*{FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""},*/ /* FIXME: not implemented yet! */
- {FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},
+ /*{FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},*/ /* FIXME: not implemented yet! */
{FMODIFIER_TYPE_LIMITS, "LIMITS", 0, "Limits",
"Restrict maximum and minimum values of F-Curve"},
{FMODIFIER_TYPE_STEPPED, "STEPPED", 0, "Stepped Interpolation",
@@ -300,7 +300,7 @@ static void rna_Driver_remove_variable(ChannelDriver *driver, ReportList *report
return;
}
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
RNA_POINTER_INVALIDATE(dvar_ptr);
}
@@ -580,7 +580,17 @@ static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max
*max = fcm->efra - fcm->sfra;
}
-static void rna_FModifier_verify_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_FModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+ AnimData *adt = BKE_animdata_from_id(id);
+ DAG_id_tag_update(id, (GS(id->name) == ID_OB) ? OB_RECALC_OB : OB_RECALC_DATA);
+ if (adt != NULL) {
+ adt->recalc |= ADT_RECALC_ANIM;
+ }
+}
+
+static void rna_FModifier_verify_data_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)ptr->data;
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
@@ -588,9 +598,11 @@ static void rna_FModifier_verify_data_update(Main *UNUSED(bmain), Scene *UNUSED(
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
fmi->verify_data(fcm);
+
+ rna_FModifier_update(bmain, scene, ptr);
}
-static void rna_FModifier_active_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_FModifier_active_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
FModifier *fm, *fmo = (FModifier *)ptr->data;
@@ -601,7 +613,8 @@ static void rna_FModifier_active_update(Main *UNUSED(bmain), Scene *UNUSED(scene
for (fm = fmo->next; fm; fm = fm->next) {
fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
}
-
+
+ rna_FModifier_update(bmain, scene, ptr);
}
static int rna_FModifierGenerator_coefficients_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
@@ -885,7 +898,7 @@ static void rna_def_fmodifier_generator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Additive",
"Values generated by this modifier are applied on top of "
"the existing values instead of overwriting them");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, generator_mode_items);
@@ -933,19 +946,19 @@ static void rna_def_fmodifier_function_generator(BlenderRNA *brna)
/* coefficients */
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Amplitude", "Scale factor determining the maximum/minimum values");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "phase_multiplier", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Phase Multiplier", "Scale factor determining the 'speed' of the function");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "phase_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Phase Offset", "Constant factor to offset time by for function");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "value_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Value Offset", "Constant factor to offset values by");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
/* flags */
prop = RNA_def_property(srna, "use_additive", PROP_BOOLEAN, PROP_NONE);
@@ -953,13 +966,13 @@ static void rna_def_fmodifier_function_generator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Additive",
"Values generated by this modifier are applied on top of "
"the existing values instead of overwriting them");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "function_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of built-in function to use");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
/* --------- */
@@ -980,18 +993,18 @@ static void rna_def_fmodifier_envelope_ctrl(BlenderRNA *brna)
prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_ui_text(prop, "Minimum Value", "Lower bound of envelope at this control-point");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_ui_text(prop, "Maximum Value", "Upper bound of envelope at this control-point");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
/* Frame */
prop = RNA_def_property(srna, "frame", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "time");
RNA_def_property_ui_text(prop, "Frame", "Frame this control-point occurs on");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
/* TODO: */
/* - selection flags (not implemented in UI yet though) */
@@ -1047,17 +1060,17 @@ static void rna_def_fmodifier_envelope(BlenderRNA *brna)
prop = RNA_def_property(srna, "reference_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "midval");
RNA_def_property_ui_text(prop, "Reference Value", "Value that envelope's influence is centered around / based on");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "default_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_ui_text(prop, "Default Minimum", "Lower distance from Reference Value for 1:1 default influence");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "default_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_ui_text(prop, "Default Maximum", "Upper distance from Reference Value for 1:1 default influence");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
/* --------- */
@@ -1087,26 +1100,26 @@ static void rna_def_fmodifier_cycles(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "before_mode");
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Before Mode", "Cycling mode to use before first keyframe");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "cycles_before", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "before_cycles");
RNA_def_property_ui_text(prop, "Before Cycles",
"Maximum number of cycles to allow before first keyframe (0 = infinite)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
/* after */
prop = RNA_def_property(srna, "mode_after", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "after_mode");
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "After Mode", "Cycling mode to use after last keyframe");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "cycles_after", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "after_cycles");
RNA_def_property_ui_text(prop, "After Cycles",
"Maximum number of cycles to allow after last keyframe (0 = infinite)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
/* --------- */
@@ -1135,46 +1148,46 @@ static void rna_def_fmodifier_limits(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_min_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_LIMIT_XMIN);
RNA_def_property_ui_text(prop, "Minimum X", "Use the minimum X value");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "use_min_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_LIMIT_YMIN);
RNA_def_property_ui_text(prop, "Minimum Y", "Use the minimum Y value");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "use_max_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_LIMIT_XMAX);
RNA_def_property_ui_text(prop, "Maximum X", "Use the maximum X value");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "use_max_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_LIMIT_YMAX);
RNA_def_property_ui_text(prop, "Maximum Y", "Use the maximum Y value");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "min_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rect.xmin");
RNA_def_property_float_funcs(prop, NULL, "rna_FModifierLimits_minx_set", "rna_FModifierLimits_minx_range");
RNA_def_property_ui_text(prop, "Minimum X", "Lowest X value to allow");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "min_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rect.ymin");
RNA_def_property_float_funcs(prop, NULL, "rna_FModifierLimits_miny_set", "rna_FModifierLimits_miny_range");
RNA_def_property_ui_text(prop, "Minimum Y", "Lowest Y value to allow");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "max_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rect.xmax");
RNA_def_property_float_funcs(prop, NULL, "rna_FModifierLimits_maxx_set", "rna_FModifierLimits_maxx_range");
RNA_def_property_ui_text(prop, "Maximum X", "Highest X value to allow");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "max_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rect.ymax");
RNA_def_property_float_funcs(prop, NULL, "rna_FModifierLimits_maxy_set", "rna_FModifierLimits_maxy_range");
RNA_def_property_ui_text(prop, "Maximum Y", "Highest Y value to allow");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
/* --------- */
@@ -1200,33 +1213,33 @@ static void rna_def_fmodifier_noise(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "modification");
RNA_def_property_enum_items(prop, prop_modification_items);
RNA_def_property_ui_text(prop, "Blend Type", "Method of modifying the existing F-Curve");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_ui_text(prop, "Scale", "Scaling (in time) of the noise");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "strength");
RNA_def_property_ui_text(prop, "Strength",
"Amplitude of the noise - the amount that it modifies the underlying curve");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "phase");
RNA_def_property_ui_text(prop, "Phase", "A random seed for the noise effect");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_text(prop, "Offset", "Time offset for the noise effect");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "depth");
RNA_def_property_ui_text(prop, "Depth", "Amount of fine level detail present in the noise");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
@@ -1247,36 +1260,36 @@ static void rna_def_fmodifier_stepped(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_step", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "step_size");
RNA_def_property_ui_text(prop, "Step Size", "Number of frames to hold each value");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_text(prop, "Offset",
"Reference number of frames before frames get held "
"(use to get hold for '1-3' vs '5-7' holding patterns)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "use_frame_start", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_STEPPED_NO_BEFORE);
RNA_def_property_ui_text(prop, "Use Start Frame", "Restrict modifier to only act after its 'start' frame");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "use_frame_end", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_STEPPED_NO_AFTER);
RNA_def_property_ui_text(prop, "Use End Frame", "Restrict modifier to only act before its 'end' frame");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start_frame");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_start_frame_range");
RNA_def_property_ui_text(prop, "Start Frame", "Frame that modifier's influence starts (if applicable)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "end_frame");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_end_frame_range");
RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if applicable)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
/* --------- */
@@ -1314,14 +1327,14 @@ static void rna_def_fmodifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_MUTED);
RNA_def_property_ui_text(prop, "Muted", "F-Curve Modifier will not be evaluated");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
RNA_def_property_ui_icon(prop, ICON_MUTE_IPO_OFF, 1);
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", FMODIFIER_FLAG_DISABLED);
RNA_def_property_ui_text(prop, "Disabled", "F-Curve Modifier has invalid settings and will not be evaluated");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
/* TODO: setting this to true must ensure that all others in stack are turned off too... */
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
@@ -1337,7 +1350,7 @@ static void rna_def_fmodifier(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Restrict Frame Range",
"F-Curve Modifier is only applied for the specified frame range to help "
"mask off effects in order to chain them");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); /* XXX: depends on UI implementation */
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
@@ -1345,32 +1358,32 @@ static void rna_def_fmodifier(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, NULL, "rna_FModifier_start_frame_set", "rna_FModifier_start_frame_range");
RNA_def_property_ui_text(prop, "Start Frame",
"Frame that modifier's influence starts (if Restrict Frame Range is in use)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "efra");
RNA_def_property_float_funcs(prop, NULL, "rna_FModifer_end_frame_set", "rna_FModifier_end_frame_range");
RNA_def_property_ui_text(prop, "End Frame",
"Frame that modifier's influence ends (if Restrict Frame Range is in use)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
prop = RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendin");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range");
RNA_def_property_ui_text(prop, "Blend In", "Number of frames from start frame for influence to take effect");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
prop = RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendout");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range");
RNA_def_property_ui_text(prop, "Blend Out", "Number of frames from end frame for influence to fade out");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
/* influence */
prop = RNA_def_property(srna, "use_influence", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_USEINFLUENCE);
RNA_def_property_ui_text(prop, "Use Influence", "F-Curve Modifier's effects will be tempered by a default factor");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); /* XXX: depends on UI implementation */
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
@@ -1379,7 +1392,7 @@ static void rna_def_fmodifier(BlenderRNA *brna)
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Influence",
"Amount of influence F-Curve Modifier will have when not fading in/out");
- RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
}
/* *********************** */
@@ -1467,11 +1480,11 @@ static void rna_def_drivervar(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem prop_type_items[] = {
- {DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", 0, "Single Property", "Use the value from some RNA property (Default)"},
- {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", 0, "Transform Channel",
+ {DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", ICON_RNA, "Single Property", "Use the value from some RNA property (Default)"},
+ {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", ICON_MANIPUL, "Transform Channel",
"Final transformation value of object or bone"},
- {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", 0, "Rotational Difference", "Use the angle between two bones"},
- {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", 0, "Distance", "Distance between two bones or objects"},
+ {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", ICON_PARTICLE_TIP, "Rotational Difference", "Use the angle between two bones"}, /* XXX: Icon... */
+ {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", ICON_FULLSCREEN_ENTER, "Distance", "Distance between two bones or objects"}, /* XXX: Icon... */
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 3c16f086325..52c04bec743 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -721,6 +721,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Use High Quality Fill */
+ prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HQ_FILL);
+ RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality method to avoid glitches (slower fps during animation playback)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Stroke Drawing Color */
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
@@ -764,18 +770,18 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gstep");
- RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames Before",
"Maximum number of frames to show before current frame "
- "(0 = show only the previous sketch)");
+ "(0 = show only the previous sketch, -1 = don't show any frames before current)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gstep_next");
- RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames After",
"Maximum number of frames to show after current frame "
- "(0 = show only the next sketch)");
+ "(0 = show only the next sketch, -1 = don't show any frames after current)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
@@ -801,14 +807,25 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
RNA_def_property_range(prop, 0.0, 2.0f);
- RNA_def_property_ui_text(prop, "Smooth", "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
+ RNA_def_property_ui_text(prop, "Smooth",
+ "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Iterations of the Smoothing factor */
+ prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
+ RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_ui_text(prop, "Iterations",
+ "Number of times to smooth newly created strokes "
+ "(smoothing strength is halved on each successive round of smoothing)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Subdivision level for new strokes */
prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sublevel");
RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Subdivision Steps", "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_property_ui_text(prop, "Subdivision Steps",
+ "Number of times to subdivide newly created strokes, for less jagged strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Flags */
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 72cd2ce55b8..161e19f581c 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -197,6 +197,8 @@ void rna_def_animdata_common(struct StructRNA *srna);
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
+void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone);
+
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget,
const char *activeset, const char *activeeditable, const char *structname,
@@ -234,7 +236,6 @@ int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current);
void rna_Object_internal_update_data(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
void rna_Mesh_update_draw(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
void rna_TextureSlot_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
-void rna_TextureSlot_brush_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
/* basic poll functions for object types */
int rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index d09cac2a383..eb87eafe16c 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -50,9 +50,12 @@
/* needed for some of the validation stuff... */
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_nla.h"
-#include "BKE_fcurve.h"
+#include "DNA_object_types.h"
+
#include "ED_anim_api.h"
/* temp constant defined for these funcs only... */
@@ -102,7 +105,14 @@ static char *rna_NlaStrip_path(PointerRNA *ptr)
return BLI_strdup("");
}
-static void rna_NlaStrip_transform_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_NlaStrip_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+
+ ANIM_id_update(scene, id);
+}
+
+static void rna_NlaStrip_transform_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
NlaStrip *strip = (NlaStrip *)ptr->data;
@@ -117,6 +127,8 @@ static void rna_NlaStrip_transform_update(Main *UNUSED(bmain), Scene *UNUSED(sce
BKE_nla_validate_state(iat->adt);
}
}
+
+ rna_NlaStrip_update(bmain, scene, ptr);
}
static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
@@ -536,45 +548,45 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX for now, not editable, since this is dangerous */
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "extendmode");
RNA_def_property_enum_items(prop, rna_enum_nla_mode_extend_items);
RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blendmode");
RNA_def_property_enum_items(prop, rna_enum_nla_mode_blend_items);
RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
/* Strip extents */
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL);
RNA_def_property_ui_text(prop, "Start Frame", "");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "end");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "End Frame", "");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
/* Blending */
prop = RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendin");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL);
RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendout");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL);
RNA_def_property_ui_text(prop, "Blend Out", "");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_auto_blend", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS);
@@ -582,7 +594,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Auto Blend In/Out",
"Number of frames for Blending In/Out is automatically determined from "
"overlapping strips");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
/* Action */
prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
@@ -591,20 +603,20 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_editable_func(prop, "rna_NlaStrip_action_editable");
RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
/* Action extents */
prop = RNA_def_property(srna, "action_frame_start", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "actstart");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
RNA_def_property_ui_text(prop, "Action Start Frame", "First frame from action to use");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
prop = RNA_def_property(srna, "action_frame_end", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "actend");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "Action End Frame", "Last frame from action to use");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
/* Action Reuse */
prop = RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE);
@@ -614,7 +626,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
* (minimum should still be > 0 though) if needed... */
RNA_def_property_range(prop, 0.1f, 1000.0f);
RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale");
@@ -623,7 +635,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
* due to numeric errors */
RNA_def_property_range(prop, 0.0001f, 1000.0f);
RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
/* Strip's F-Curves */
prop = RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE);
@@ -647,11 +659,11 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
/* TODO: should the animated_influence/time settings be animatable themselves? */
prop = RNA_def_property(srna, "use_animated_influence", PROP_BOOLEAN, PROP_NONE);
@@ -659,19 +671,19 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set");
RNA_def_property_ui_text(prop, "Animated Influence",
"Influence setting is controlled by an F-Curve rather than automatically determined");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_animated_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME);
RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set");
RNA_def_property_ui_text(prop, "Animated Strip Time",
"Strip time is controlled by an F-Curve rather than automatically determined");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_animated_time_cyclic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME_CYCLIC);
RNA_def_property_ui_text(prop, "Cyclic Strip Time", "Cycle the animated time within the action start & end");
- RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update"); /* is there a better update flag? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
/* settings */
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
@@ -689,21 +701,21 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_reverse", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE);
RNA_def_property_ui_text(prop, "Reversed",
"NLA Strip is played back in reverse order (only when timing is "
"automatically determined)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_sync_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SYNC_LENGTH);
RNA_def_property_ui_text(prop, "Sync Action Length",
"Update range of frames referenced from action "
"after tweaking strip and its keyframes");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
}
static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
@@ -775,7 +787,7 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Solo",
"NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the "
"same AnimData block are disabled)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaTrack_solo_set");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
@@ -786,7 +798,7 @@ static void rna_def_nlatrack(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED);
RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index ccbabb2b238..3221e93fe84 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5892,6 +5892,12 @@ static void def_cmp_colorbalance(StructRNA *srna)
RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
RNA_def_property_ui_text(prop, "Slope", "Correction for Highlights");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl");
+
+ prop = RNA_def_property(srna, "offset_basis", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -1.0, 1.0, 1.0, 2);
+ RNA_def_property_ui_text(prop, "Basis", "Support negative color by using this as the RGB basis");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl");
}
static void def_cmp_huecorrect(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 031ea89cff6..9ebef9db454 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -267,7 +267,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
switch (ob->type) {
case OB_MESH:
EDBM_mesh_load(ob);
- EDBM_mesh_make(scene->toolsettings, ob);
+ EDBM_mesh_make(scene->toolsettings, ob, true);
DAG_id_tag_update(ob->data, 0);
@@ -301,7 +301,7 @@ static void rna_Object_select_update(Main *UNUSED(bmain), Scene *scene, PointerR
{
if (scene) {
Object *ob = (Object *)ptr->id.data;
- short mode = ob->flag & SELECT ? BA_SELECT : BA_DESELECT;
+ short mode = (ob->flag & SELECT) ? BA_SELECT : BA_DESELECT;
ED_base_object_select(BKE_scene_base_find(scene, ob), mode);
}
}
@@ -309,7 +309,7 @@ static void rna_Object_select_update(Main *UNUSED(bmain), Scene *scene, PointerR
static void rna_Base_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Base *base = (Base *)ptr->data;
- short mode = base->flag & BA_SELECT ? BA_SELECT : BA_DESELECT;
+ short mode = (base->flag & BA_SELECT) ? BA_SELECT : BA_DESELECT;
ED_base_object_select(base, mode);
}
@@ -1134,7 +1134,7 @@ static void rna_GameObjectSettings_state_get(PointerRNA *ptr, int *values)
{
Object *ob = (Object *)ptr->data;
int i;
- int all_states = (ob->scaflag & OB_ALLSTATE ? 1 : 0);
+ int all_states = (ob->scaflag & OB_ALLSTATE) ? 1 : 0;
memset(values, 0, sizeof(int) * OB_MAX_STATES);
for (i = 0; i < OB_MAX_STATES; i++) {
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index d8f1f944933..06823a26c77 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -43,6 +43,8 @@
#include "BLT_translation.h"
+#include "UI_resources.h"
+
#include "WM_types.h"
@@ -65,26 +67,26 @@ EnumPropertyItem rna_enum_posebone_rotmode_items[] = {
/* Bone and Group Color Sets */
EnumPropertyItem rna_enum_color_sets_items[] = {
{0, "DEFAULT", 0, "Default Colors", ""},
- {1, "THEME01", 0, "01 - Theme Color Set", ""},
- {2, "THEME02", 0, "02 - Theme Color Set", ""},
- {3, "THEME03", 0, "03 - Theme Color Set", ""},
- {4, "THEME04", 0, "04 - Theme Color Set", ""},
- {5, "THEME05", 0, "05 - Theme Color Set", ""},
- {6, "THEME06", 0, "06 - Theme Color Set", ""},
- {7, "THEME07", 0, "07 - Theme Color Set", ""},
- {8, "THEME08", 0, "08 - Theme Color Set", ""},
- {9, "THEME09", 0, "09 - Theme Color Set", ""},
- {10, "THEME10", 0, "10 - Theme Color Set", ""},
- {11, "THEME11", 0, "11 - Theme Color Set", ""},
- {12, "THEME12", 0, "12 - Theme Color Set", ""},
- {13, "THEME13", 0, "13 - Theme Color Set", ""},
- {14, "THEME14", 0, "14 - Theme Color Set", ""},
- {15, "THEME15", 0, "15 - Theme Color Set", ""},
- {16, "THEME16", 0, "16 - Theme Color Set", ""},
- {17, "THEME17", 0, "17 - Theme Color Set", ""},
- {18, "THEME18", 0, "18 - Theme Color Set", ""},
- {19, "THEME19", 0, "19 - Theme Color Set", ""},
- {20, "THEME20", 0, "20 - Theme Color Set", ""},
+ {1, "THEME01", VICO_COLORSET_01_VEC, "01 - Theme Color Set", ""},
+ {2, "THEME02", VICO_COLORSET_02_VEC, "02 - Theme Color Set", ""},
+ {3, "THEME03", VICO_COLORSET_03_VEC, "03 - Theme Color Set", ""},
+ {4, "THEME04", VICO_COLORSET_04_VEC, "04 - Theme Color Set", ""},
+ {5, "THEME05", VICO_COLORSET_05_VEC, "05 - Theme Color Set", ""},
+ {6, "THEME06", VICO_COLORSET_06_VEC, "06 - Theme Color Set", ""},
+ {7, "THEME07", VICO_COLORSET_07_VEC, "07 - Theme Color Set", ""},
+ {8, "THEME08", VICO_COLORSET_08_VEC, "08 - Theme Color Set", ""},
+ {9, "THEME09", VICO_COLORSET_09_VEC, "09 - Theme Color Set", ""},
+ {10, "THEME10", VICO_COLORSET_10_VEC, "10 - Theme Color Set", ""},
+ {11, "THEME11", VICO_COLORSET_11_VEC, "11 - Theme Color Set", ""},
+ {12, "THEME12", VICO_COLORSET_12_VEC, "12 - Theme Color Set", ""},
+ {13, "THEME13", VICO_COLORSET_13_VEC, "13 - Theme Color Set", ""},
+ {14, "THEME14", VICO_COLORSET_14_VEC, "14 - Theme Color Set", ""},
+ {15, "THEME15", VICO_COLORSET_15_VEC, "15 - Theme Color Set", ""},
+ {16, "THEME16", VICO_COLORSET_16_VEC, "16 - Theme Color Set", ""},
+ {17, "THEME17", VICO_COLORSET_17_VEC, "17 - Theme Color Set", ""},
+ {18, "THEME18", VICO_COLORSET_18_VEC, "18 - Theme Color Set", ""},
+ {19, "THEME19", VICO_COLORSET_19_VEC, "19 - Theme Color Set", ""},
+ {20, "THEME20", VICO_COLORSET_20_VEC, "20 - Theme Color Set", ""},
{-1, "CUSTOM", 0, "Custom Color Set", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -532,7 +534,7 @@ static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int typ
static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr)
{
bConstraint *con = con_ptr->data;
- const short is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
+ const bool is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
Object *ob = (Object *)id;
if (BLI_findindex(&pchan->constraints, con) == -1) {
@@ -872,6 +874,50 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rotation Mode", "");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ /* Curved bones settings - Applied on top of restpose values */
+ rna_def_bone_curved_common(srna, true);
+
+ /* Custom BBone next/prev sources */
+ prop = RNA_def_property(srna, "use_bbone_custom_handles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_HANDLES);
+ RNA_def_property_ui_text(prop, "Use Custom Handle References",
+ "Use custom reference bones as handles for B-Bones instead of next/previous bones, "
+ "leave these blank to use only B-Bone offset properties to control the shape");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev");
+ RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "B-Bone Start Handle",
+ "Bone that serves as the start handle for the B-Bone curve");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL);
+ RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle",
+ "Use treat custom start handle position as a relative value");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_next");
+ RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "B-Bone End Handle",
+ "Bone that serves as the end handle for the B-Bone curve");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL);
+ RNA_def_property_ui_text(prop, "Relative B-Bone End Handle",
+ "Use treat custom end handle position as a relative value");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
/* transform matrices - should be read-only since these are set directly by AnimSys evaluation */
prop = RNA_def_property(srna, "matrix_channel", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "chan_mat");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 94223f7f7da..e89edaf74ad 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -860,7 +860,7 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
- const char is_render = (id && GS(id->name) == ID_SCE);
+ const bool is_render = (id && GS(id->name) == ID_SCE);
/* see note below on why this is */
const char chan_flag = BKE_imtype_valid_channels(imf->imtype, true) | (is_render ? IMA_CHAN_FLAG_BW : 0);
@@ -927,7 +927,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
- const char is_render = (id && GS(id->name) == ID_SCE);
+ const bool is_render = (id && GS(id->name) == ID_SCE);
/* note, we need to act differently for render
* where 'BW' will force grayscale even if the output format writes
@@ -1767,6 +1767,11 @@ static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.unified_paint_settings");
}
+static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.curve_paint_settings");
+}
+
/* generic function to recalc geometry */
static void rna_EditMesh_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
@@ -2497,6 +2502,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "UnifiedPaintSettings");
RNA_def_property_ui_text(prop, "Unified Paint Settings", NULL);
+ /* Curve Paint Settings */
+ prop = RNA_def_property(srna, "curve_paint_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "CurvePaintSettings");
+ RNA_def_property_ui_text(prop, "Curve Paint Settings", NULL);
+
/* Mesh Statistics */
prop = RNA_def_property(srna, "statvis", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2595,6 +2606,100 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
"when unlocked brush size is given in pixels");
}
+
+static void rna_def_curve_paint_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "CurvePaintSettings", NULL);
+ RNA_def_struct_path_func(srna, "rna_CurvePaintSettings_path");
+ RNA_def_struct_ui_text(srna, "Curve Paint Settings", "");
+
+ static EnumPropertyItem curve_type_items[] = {
+ {CU_POLY, "POLY", 0, "Poly", ""},
+ {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "curve_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "curve_type");
+ RNA_def_property_enum_items(prop, curve_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of curve to use for new strokes");
+
+ prop = RNA_def_property(srna, "use_corners_detect", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_CORNERS_DETECT);
+ RNA_def_property_ui_text(prop, "Detect Corners", "Detect corners and use non-aligned handles");
+
+ prop = RNA_def_property(srna, "use_pressure_radius", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_PRESSURE_RADIUS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Map tablet pressure to curve radius");
+
+ prop = RNA_def_property(srna, "use_stroke_endpoints", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS);
+ RNA_def_property_ui_text(prop, "Only First", "Use the start of the stroke for the depth");
+
+ prop = RNA_def_property(srna, "use_offset_absolute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS);
+ RNA_def_property_ui_text(prop, "Absolute Offset", "Apply a fixed offset (don't scale by the radius)");
+
+ prop = RNA_def_property(srna, "error_threshold", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less precise line");
+
+ prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0, M_PI);
+ RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners");
+
+ prop = RNA_def_property(srna, "radius_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Radius Min",
+ "Minimum radius when the minimum pressure is applied (also the minimum when tapering)");
+
+ prop = RNA_def_property(srna, "radius_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Radius Max",
+ "Radius to use when the maximum pressure is applied (or when a tablet isn't used)");
+
+ prop = RNA_def_property(srna, "radius_taper_start", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Radius Min", "Taper factor for the radius of each point along the curve");
+
+ prop = RNA_def_property(srna, "radius_taper_end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Radius Max", "Taper factor for the radius of each point along the curve");
+
+ prop = RNA_def_property(srna, "surface_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -10.0, 10.0);
+ RNA_def_property_ui_range(prop, -1.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Offset the stroke from the surface");
+
+ static EnumPropertyItem depth_mode_items[] = {
+ {CURVE_PAINT_PROJECT_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {CURVE_PAINT_PROJECT_SURFACE, "SURFACE", 0, "Surface", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "depth_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "depth_mode");
+ RNA_def_property_enum_items(prop, depth_mode_items);
+ RNA_def_property_ui_text(prop, "Depth", "Method of projecting depth");
+
+ static EnumPropertyItem surface_plane_items[] = {
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, "NORMAL_VIEW", 0, "Normal/View", "Draw perpendicular to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE, "NORMAL_SURFACE", 0, "Normal/Surface", "Draw aligned to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_VIEW, "VIEW", 0, "View", "Draw aligned to the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "surface_plane", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "surface_plane");
+ RNA_def_property_enum_items(prop, surface_plane_items);
+ RNA_def_property_ui_text(prop, "Plane", "Plane for projected stroke");
+}
+
static void rna_def_statvis(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6720,6 +6825,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
rna_def_unified_paint_settings(brna);
+ rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
rna_def_unit_settings(brna);
rna_def_scene_image_format_data(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 6d7506f3911..74fb4a08eda 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -55,6 +55,7 @@
#include "BKE_writeavi.h"
#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#ifdef WITH_PYTHON
@@ -145,13 +146,22 @@ static void rna_Scene_ray_cast(
{
normalize_v3(direction);
- if (snapObjectsRayEx(
- scene, NULL, NULL, NULL, NULL,
- NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(
+ G.main, scene, 0);
+
+ bool ret = ED_transform_snap_object_project_ray_ex(
+ sctx,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .snap_to = SCE_SNAP_MODE_FACE,
+ },
origin, direction, &ray_dist,
- r_location, r_normal, NULL, r_index,
- r_ob, (float(*)[4])r_obmat))
- {
+ r_location, r_normal, r_index,
+ r_ob, (float(*)[4])r_obmat);
+
+ ED_transform_snap_object_context_destroy(sctx);
+
+ if (ret) {
*r_success = true;
}
else {
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index e8a45e6a77d..68d4f7f7e51 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2330,6 +2330,16 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+ prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "shadow_color");
+ RNA_def_property_ui_text(prop, "Shadow Color", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "Location of the text");
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index ba3198a4843..9a31952b84b 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -191,6 +191,29 @@ static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr, int lengt
return length[0];
}
+static int rna_SmokeModifier_heat_grid_get_length(
+ PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ float *heat = NULL;
+ int size = 0;
+
+ /* Heat data is always low-resolution. */
+ if (sds->fluid) {
+ size = sds->res[0] * sds->res[1] * sds->res[2];
+ heat = smoke_get_heat(sds->fluid);
+ }
+
+ length[0] = (heat) ? size : 0;
+#else
+ (void)ptr;
+ length[0] = 0;
+#endif
+ return length[0];
+}
+
static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
@@ -293,6 +316,34 @@ static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
#endif
}
+static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_SmokeModifier_heat_grid_get_length(ptr, length);
+ float *heat;
+
+ BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+ heat = smoke_get_heat(sds->fluid);
+
+ if (heat != NULL) {
+ /* scale heat values from -2.0-2.0 to -1.0-1.0. */
+ for (int i = 0; i < size; i++) {
+ values[i] = heat[i] * 0.5f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+#else
+ UNUSED_VARS(ptr, values);
+#endif
+}
+
static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
@@ -563,6 +614,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_color_grid_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
+ prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_heat_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
+
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index ad1ca12d4ea..1e88585a286 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -225,7 +225,7 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value)
BKE_texture_type_set(tex, value);
}
-void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -244,8 +244,12 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, id);
break;
case ID_BR:
+ {
+ MTex *mtex = ptr->data;
+ BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
WM_main_add_notifier(NC_BRUSH, id);
break;
+ }
case ID_LS:
WM_main_add_notifier(NC_LINESTYLE, id);
break;
@@ -266,24 +270,6 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
}
}
-void rna_TextureSlot_brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- ID *id = ptr->id.data;
-
- DAG_id_tag_update(id, 0);
-
- switch (GS(id->name)) {
- case ID_BR:
- {
- MTex *mtex = ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
- break;
- }
- }
- rna_TextureSlot_update(bmain, scene, ptr);
-}
-
-
char *rna_TextureSlot_path(PointerRNA *ptr)
{
MTex *mtex = ptr->data;
@@ -675,14 +661,14 @@ static void rna_def_mtex(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "ofs");
RNA_def_property_ui_range(prop, -10, 10, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Offset", "Fine tune of the texture mapping X, Y and Z locations");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, -100, 100, 10, 2);
RNA_def_property_ui_text(prop, "Size", "Set scaling for the texture's X, Y and Z sizes");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index a9901fd3a50..2564bdb800f 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1777,8 +1777,8 @@ static void rna_def_trackingReconstructedCameras(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Return interpolated camera matrix for a given frame");
RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find camera for", MINFRAME, MAXFRAME);
- parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, FLT_MIN, FLT_MAX, "Matrix",
- "Interpolated camera matrix for a given frame", FLT_MIN, FLT_MAX);
+ parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, -FLT_MAX, FLT_MAX, "Matrix",
+ "Interpolated camera matrix for a given frame", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index efd302ce451..0fbc1ce1854 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -139,7 +139,7 @@ static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
@@ -149,7 +149,7 @@ static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene),
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
/* force setting drawable again */
wmWindowManager *wm = bmain->wm.first;
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 51c410e44e1..0d11414c878 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -263,6 +263,7 @@ EnumPropertyItem rna_enum_event_type_items[] = {
{QUOTEKEY, "QUOTE", 0, "\"", ""},
{ACCENTGRAVEKEY, "ACCENT_GRAVE", 0, "`", ""},
{MINUSKEY, "MINUS", 0, "-", ""},
+ {PLUSKEY, "PLUS", 0, "+", ""},
{SLASHKEY, "SLASH", 0, "/", ""},
{BACKSLASHKEY, "BACK_SLASH", 0, "\\", ""},
{EQUALKEY, "EQUAL", 0, "=", ""},
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index d9ace45453c..567505ea45d 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -124,6 +124,7 @@ static void updateDepsgraph(ModifierData *md,
ArmatureModifierData *amd = (ArmatureModifierData *)md;
if (amd->object != NULL) {
DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ DEG_add_object_relation(node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier");
}
}
@@ -206,6 +207,7 @@ ModifierTypeInfo modifierType_Armature = {
/* structSize */ sizeof(ArmatureModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 32c3d41c4b6..33e5b3615d9 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -498,6 +498,7 @@ ModifierTypeInfo modifierType_Cast = {
/* structSize */ sizeof(CastModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index bebfbbe9a80..ff0c6500479 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -189,7 +189,7 @@ static void deformVerts(ModifierData *md, Object *ob,
/* check if GUI setting has changed for bvh */
if (collmd->bvhtree) {
- if (ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree)) {
+ if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
BLI_bvhtree_free(collmd->bvhtree);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 6e2d746c858..9bc96e593fd 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -164,6 +164,7 @@ ModifierTypeInfo modifierType_Curve = {
/* structSize */ sizeof(CurveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index e175f4943a7..83c4ca7984c 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -139,20 +139,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
+ Object *ob,
struct DepsNodeHandle *node)
{
HookModifierData *hmd = (HookModifierData *)md;
if (hmd->object != NULL) {
if (hmd->subtarget[0]) {
- /* TODO(sergey): Hpw do we add relation to bone here? */
- //DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_EVAL_POSE, "Hook Modifier");
+ DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
}
else {
DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
}
+ /* We need own transformation as well. */
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
struct HookData_cb {
@@ -416,6 +417,7 @@ ModifierTypeInfo modifierType_Hook = {
/* structSize */ sizeof(HookModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index d4f02d923d3..ce3fdc4bbe8 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -339,7 +339,6 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
zero_v3(ni);
- num_fni = 0;
num_fni = sys->ringf_map[i].count;
for (fi = 0; fi < num_fni; fi++) {
const unsigned int *vin;
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 0f49ce6cfbf..7d4701e3ef2 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -156,6 +156,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* structSize */ sizeof(LatticeModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 92926ed9424..aa3e3ebcf7e 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -299,6 +299,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* structSize */ sizeof(MeshCacheModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index e3c94a1a4df..3f34319d25f 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -520,6 +520,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* structSize */ sizeof(MeshDeformModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index a90a51e9ddc..e77cc655c16 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -435,7 +435,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);
/* can happen in when size is small, avoid bad array lookups later and quit now */
- if (!finite(size_co_inv)) {
+ if (!isfinite(size_co_inv)) {
return derivedData;
}
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index a9919cadd16..633311c2b87 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -194,6 +194,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 588b56d6aba..c68f2651191 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -366,6 +366,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index d958badc33c..98a1412d0c6 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -65,6 +65,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* structSize */ sizeof(SoftbodyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_RequiresOriginalData |
eModifierTypeFlag_Single,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 27d3bac59ec..b38de140a91 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -374,6 +374,7 @@ ModifierTypeInfo modifierType_Warp = {
/* structSize */ sizeof(WarpModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index f13eeb3185e..683649ed1c0 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -384,6 +384,7 @@ ModifierTypeInfo modifierType_Wave = {
/* structSize */ sizeof(WaveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index f126e499fc2..0968d2aa5e0 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -506,9 +506,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
new_w[i] = dist;
}
else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
- const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS);
- const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES);
- const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES);
+ const bool use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS) != 0;
+ const bool use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES) != 0;
+ const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0;
if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
DerivedMesh *target_dm = obr->derivedFinal;
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 2f96bdbe3df..4cb39e0f13b 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -55,7 +55,6 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BKE_blender.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index 3b000d49822..d5dac3b7ff8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -69,7 +69,7 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
}
- return 0;
+ return false;
}
void register_node_type_sh_lamp(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index 2af6e19565b..2044f5390cc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -42,6 +42,15 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
{ -1, 0, "" }
};
+static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
+ bNode *node,
+ bNodeInstanceKey UNUSED(key))
+{
+ TexMapping *texmap = node->storage;
+ BKE_texture_mapping_init(texmap);
+ return NULL;
+}
+
/* do the regular mapping options for blender textures */
static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
@@ -85,12 +94,12 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
GPUNodeLink *tdomin = GPU_uniform(&domin);
GPUNodeLink *tdomax = GPU_uniform(&domax);
- int result = GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
+ GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
- if (result && texmap->type == TEXMAP_TYPE_NORMAL)
+ if (texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
- return result;
+ return true;
}
void register_node_type_sh_mapping(void)
@@ -103,7 +112,7 @@ void register_node_type_sh_mapping(void)
node_type_size(&ntype, 320, 160, 360);
node_type_init(&ntype, node_shader_init_mapping);
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_mapping);
+ node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 13bf2a0fe43..642e5b296be 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -46,12 +46,111 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
-static int gpu_shader_normal_map(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+ {
+ if (data) {
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+
+ NodeShaderNormalMap *nm = node->storage;
+
+ float strength, vecIn[3];
+ nodestack_get_vec(&strength, SOCK_FLOAT, in[0]);
+ nodestack_get_vec(vecIn, SOCK_VECTOR, in[1]);
+
+ vecIn[0] = -2 * (vecIn[0] - 0.5f);
+ vecIn[1] = 2 * (vecIn[1] - 0.5f);
+ vecIn[2] = 2 * (vecIn[2] - 0.5f);
+
+ CLAMP_MIN(strength, 0.0f);
+
+ float *N = shi->vno;
+ int uv_index = 0;
+ switch (nm->space) {
+ case SHD_NORMAL_MAP_TANGENT:
+ if (nm->uv_map[0]) {
+ /* find uv map by name */
+ for (int i = 0; i < shi->totuv; i++) {
+ if (STREQ(shi->uv[i].name, nm->uv_map)) {
+ uv_index = i;
+ break;
+ }
+ }
+ }
+ else {
+ uv_index = shi->actuv;
+ }
+
+ float *T = shi->tangents[uv_index];
+
+ float B[3];
+ cross_v3_v3v3(B, N, T);
+ mul_v3_fl(B, T[3]);
+
+ for (int j = 0; j < 3; j++)
+ out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
+ interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
+ break;
+
+ case SHD_NORMAL_MAP_OBJECT:
+ case SHD_NORMAL_MAP_BLENDER_OBJECT:
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
+ interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
+ break;
+
+ case SHD_NORMAL_MAP_WORLD:
+ case SHD_NORMAL_MAP_BLENDER_WORLD:
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
+ interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
+ break;
+ }
+ normalize_v3(out[0]->vec);
+ }
+}
+
+static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- GPUNodeLink *normal;
- GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &normal);
+ NodeShaderNormalMap *nm = node->storage;
+ GPUNodeLink *negnorm;
+ GPUNodeLink *realnorm;
+ GPUNodeLink *strength;
+
+ float d[4] = {0, 0, 0, 0};
+
+ if (in[0].link)
+ strength = in[0].link;
+ else
+ strength = GPU_uniform(in[0].vec);
+
+ if (in[1].link) {
+ GPU_link(mat, "color_to_normal", in[1].link, &realnorm);
+ GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
+ }
+
+ GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
+ GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &negnorm);
+
+ if (in[1].link) {
+ switch (nm->space) {
+ case SHD_NORMAL_MAP_TANGENT:
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &out[0].link);
+ break;
+ case SHD_NORMAL_MAP_OBJECT:
+ case SHD_NORMAL_MAP_BLENDER_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &out[0].link);
+ break;
+ case SHD_NORMAL_MAP_WORLD:
+ case SHD_NORMAL_MAP_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &out[0].link);
+ break;
+ }
+ }
+
+ if (out[0].link) {
+ GPU_link(mat, "vec_math_mix", strength, out[0].link, negnorm, &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ }
- return GPU_stack_link(mat, "node_normal_map", in, out, normal);
+ return true;
}
/* node type definition */
@@ -60,12 +159,13 @@ void register_node_type_sh_normal_map(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_normal_map);
node_type_storage(&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, gpu_shader_normal_map);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
index bd98dc1279c..336536b21ee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c
@@ -43,7 +43,7 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, bNode *UNUSED(node)
GPU_stack_link(mat, "node_output_material", in, out, &outlink);
GPU_material_output_link(mat, outlink);
- return 1;
+ return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c
index ad7389fd56e..f95cc842720 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c
@@ -42,7 +42,7 @@ static int node_shader_gpu_output_world(GPUMaterial *mat, bNode *UNUSED(node), b
GPU_stack_link(mat, "node_output_world", in, out, &outlink);
GPU_material_output_link(mat, outlink);
- return 1;
+ return true;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 2b43667a009..2f8f95b0675 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -60,7 +60,6 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
- int ret;
if (!ima)
return GPU_stack_link(mat, "node_tex_environment_empty", in, out);
@@ -77,21 +76,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
node_shader_gpu_tex_mapping(mat, node, in, out);
if (tex->projection == SHD_PROJ_EQUIRECTANGULAR)
- ret = GPU_stack_link(mat, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
else
- ret = GPU_stack_link(mat, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
- if (ret) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat))
- {
- GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+ GPU_material_do_color_management(mat))
+ {
+ GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
}
+ BKE_image_release_ibuf(ima, ibuf, NULL);
- return ret;
+ return true;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index f87e792399b..f0a8cda045e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -60,7 +60,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
- int ret;
if (!ima)
return GPU_stack_link(mat, "node_tex_image_empty", in, out);
@@ -70,19 +69,18 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
node_shader_gpu_tex_mapping(mat, node, in, out);
- ret = GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
- if (ret) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat))
- {
- GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
+ ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+ GPU_material_do_color_management(mat))
+ {
+ GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
}
+ BKE_image_release_ibuf(ima, ibuf, NULL);
- return ret;
+ return true;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
index 5cdbaf444f8..6edf6c2a0b4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -123,22 +123,20 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
if (tex && tex->type == TEX_IMAGE && tex->ima) {
GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
- int ret = GPU_stack_link(mat, "texture_image", in, out, texlink);
+ GPU_stack_link(mat, "texture_image", in, out, texlink);
- if (ret) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat))
- {
- GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
- }
- BKE_image_release_ibuf(tex->ima, ibuf, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
+ if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+ GPU_material_do_color_management(mat))
+ {
+ GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
}
+ BKE_image_release_ibuf(tex->ima, ibuf, NULL);
- return ret;
+ return true;
}
- else
- return 0;
+
+ return false;
}
void register_node_type_sh_texture(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index 45a11c5f799..26045dfca04 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
@@ -130,10 +130,10 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN
}
break;
default:
- return 0;
+ return false;
}
- return 1;
+ return true;
}
void register_node_type_sh_vect_math(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index 35a12d52b2d..3c165cfcb8a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -157,8 +157,6 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecDat
struct GPUNodeLink *inputlink;
struct GPUNodeLink *fromto;
- int ret = 0;
-
const char *vtransform = "direction_transform_m4v3";
const char *ptransform = "point_transform_m4v3";
const char *func_name = 0;
@@ -180,24 +178,24 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecDat
/* For cycles we have inverted Z */
/* TODO: pass here the correct matrices */
if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
- ret = GPU_link(mat, "invert_z", inputlink, &inputlink);
+ GPU_link(mat, "invert_z", inputlink, &inputlink);
}
- ret = GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
- ret = GPU_link(mat, "invert_z", out[0].link, &out[0].link);
+ GPU_link(mat, "invert_z", out[0].link, &out[0].link);
}
}
else {
- ret = GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
}
}
else
- ret = GPU_link(mat, "set_rgb", inputlink, &out[0].link);
+ GPU_link(mat, "set_rgb", inputlink, &out[0].link);
if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL)
- return GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
- return ret;
+ return true;
}
void register_node_type_sh_vect_transform(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
index a271162bd19..4861871e8d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
@@ -42,7 +42,7 @@ static bNodeSocketTemplate sh_node_volume_absorption_out[] = {
static int node_shader_gpu_volume_absorption(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
{
- return 0;
+ return false;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
index cb1377348e5..0c5647b4ba8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
@@ -43,7 +43,7 @@ static bNodeSocketTemplate sh_node_volume_scatter_out[] = {
static int node_shader_gpu_volume_scatter(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
{
- return 0;
+ return false;
}
/* node type definition */
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 9000cbb90d8..2263c271ccf 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -53,7 +53,6 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BKE_blender.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 4d114e182c0..648ef132655 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -138,7 +138,7 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
bool result = false;
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
float margin_distance = (float)collpair->distance - epsilon2;
float mag_v_rel;
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index ce8f1247919..a0722af522b 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -223,7 +223,11 @@ static PyObject *bpy_bmfaceseq_get(BPy_BMesh *self, void *UNUSED(closure))
}
PyDoc_STRVAR(bpy_bmloopseq_doc,
-"This meshes face sequence (read-only).\n\n:type: :class:`BMLoopSeq`"
+"This meshes loops (read-only).\n\n:type: :class:`BMLoopSeq`\n"
+"\n"
+".. note::\n"
+"\n"
+" Loops must be accessed via faces, this is only exposed for layer access.\n"
);
static PyObject *bpy_bmloopseq_get(BPy_BMesh *self, void *UNUSED(closure))
{
@@ -912,7 +916,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
/* python won't ensure matching uv/mtex */
BM_mesh_cd_validate(bm);
- BM_mesh_bm_to_me(bm, me, false);
+ BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
@@ -1071,7 +1075,10 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
bm = self->bm;
- BM_mesh_bm_from_me(bm, me, use_fnorm, use_shape_key, shape_key_index + 1);
+ BM_mesh_bm_from_me(
+ bm, me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = use_fnorm, .use_shapekey = use_shape_key, .active_shapekey = shape_key_index + 1,
+ }));
Py_RETURN_NONE;
}
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 0dfff9b4a7b..69f1e297b43 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -332,17 +332,21 @@ PyDoc_STRVAR(py_blf_shadow_doc,
static PyObject *py_blf_shadow(PyObject *UNUSED(self), PyObject *args)
{
int level, fontid;
- float r, g, b, a;
+ float rgba[4];
- if (!PyArg_ParseTuple(args, "iiffff:blf.shadow", &fontid, &level, &r, &g, &b, &a))
+ if (!PyArg_ParseTuple(
+ args, "iiffff:blf.shadow",
+ &fontid, &level, &rgba[0], &rgba[1], &rgba[2], &rgba[3]))
+ {
return NULL;
+ }
if (level != 0 && level != 3 && level != 5) {
PyErr_SetString(PyExc_TypeError, "blf.shadow expected arg to be in (0, 3, 5)");
return NULL;
}
- BLF_shadow(fontid, level, r, g, b, a);
+ BLF_shadow(fontid, level, rgba);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index dd32c913f78..7f13a7a4d94 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -45,7 +45,7 @@
#ifdef _WIN32
#include "BLI_path_util.h" /* BLI_setenv() */
-#include "BLI_math_base.h" /* finite() */
+#include "BLI_math_base.h" /* isfinite() */
#endif
/* array utility function */
@@ -1026,7 +1026,7 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
if (val == -1 && PyErr_Occurred()) {
ok = false;
}
- else if (!finite(val)) {
+ else if (!isfinite(val)) {
*value = 0.0;
}
else {
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index c09b39139c2..5bbfb4912e6 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -35,7 +35,7 @@
#include "BKE_appdir.h"
#include "BKE_global.h" /* XXX, G.main only */
-#include "BKE_blender.h"
+#include "BKE_blender_version.h"
#include "BKE_bpath.h"
#include "RNA_types.h"
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 595bb7b0f22..17617a231b2 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -48,7 +48,7 @@
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
-#include "BKE_blender.h"
+#include "BKE_blender_version.h"
#include "BKE_global.h"
#include "DNA_ID.h"
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index f9c0982a4c3..9b477e384db 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -273,6 +273,22 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
if (driver_arg == NULL) {
driver_arg = PyFloat_FromDouble(0.0);
+ dvar->curval = 0.0f;
+ }
+ else {
+ /* no need to worry about overflow here, values from RNA are within limits. */
+ if (PyFloat_CheckExact(driver_arg)) {
+ dvar->curval = (float)PyFloat_AsDouble(driver_arg);
+ }
+ else if (PyLong_CheckExact(driver_arg)) {
+ dvar->curval = (float)PyLong_AsLong(driver_arg);
+ }
+ else if (PyBool_Check(driver_arg)) {
+ dvar->curval = (driver_arg == Py_True);
+ }
+ else {
+ dvar->curval = 0.0f;
+ }
}
}
else
@@ -331,7 +347,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
if (use_gil)
PyGILState_Release(gilstate);
- if (finite(result)) {
+ if (isfinite(result)) {
return (float)result;
}
else {
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index b559623f619..11af0836e1c 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -31,10 +31,6 @@
#include <Python.h>
-#ifdef WIN32
-# include "BLI_math_base.h" /* finite */
-#endif
-
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index ab239bbfa8c..f582cebb260 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -35,7 +35,7 @@
#include "BLI_path_util.h"
#include "BKE_library.h"
-#include "BKE_blender.h"
+#include "BKE_blendfile.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -66,13 +66,15 @@ PyDoc_STRVAR(bpy_lib_write_doc,
" :type relative_remap: bool\n"
" :arg fake_user: When True, data-blocks will be written with fake-user flag enabled.\n"
" :type fake_user: bool\n"
+" :arg compress: When True, write a compressed blend file.\n"
+" :type compress: bool\n"
);
static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {
"filepath", "datablocks",
/* optional */
- "relative_remap", "fake_user",
+ "relative_remap", "fake_user", "compress",
NULL,
};
@@ -80,15 +82,16 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject
const char *filepath;
char filepath_abs[FILE_MAX];
PyObject *datablocks = NULL;
- bool use_relative_remap = false, use_fake_user = false;
+ bool use_relative_remap = false, use_fake_user = false, use_compress = false;
if (!PyArg_ParseTupleAndKeywords(
args, kwds,
- "sO!|$O&O&:write", (char **)kwlist,
+ "sO!|$O&O&O&:write", (char **)kwlist,
&filepath,
&PySet_Type, &datablocks,
PyC_ParseBool, &use_relative_remap,
- PyC_ParseBool, &use_fake_user))
+ PyC_ParseBool, &use_fake_user,
+ PyC_ParseBool, &use_compress))
{
return NULL;
}
@@ -100,6 +103,10 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject
write_flags |= G_FILE_RELATIVE_REMAP;
}
+ if (use_compress) {
+ write_flags |= G_FILE_COMPRESS;
+ }
+
BLI_strncpy(filepath_abs, filepath, FILE_MAX);
BLI_path_abs(filepath_abs, G.main->name);
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index ce9b3e754ac..bce1d923462 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -1314,7 +1314,7 @@ static int icon_id_from_name(const char *name)
return 0;
}
-static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, int *defvalue, const short is_enum_flag)
+static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, int *defvalue, const bool is_enum_flag)
{
EnumPropertyItem *items;
PyObject *item;
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 75490a18ab0..33ac58dadb1 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -7363,12 +7363,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PointerRNA funcptr;
int err = 0, i, ret_len = 0, arg_count;
int flag = RNA_function_flag(func);
- const char is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
- const char is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
-
- /* annoying!, need to check if the screen gets set to NULL which is a
- * hint that the file was actually re-loaded. */
- char is_valid_wm;
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+ const bool is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
PropertyRNA *pret_single = NULL;
void *retdata_single = NULL;
@@ -7395,7 +7391,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (C == NULL)
C = BPy_GetContext();
- is_valid_wm = (CTX_wm_manager(C) != NULL);
+ /* annoying!, need to check if the screen gets set to NULL which is a
+ * hint that the file was actually re-loaded. */
+ const bool is_valid_wm = (CTX_wm_manager(C) != NULL);
bpy_context_set(C, &gilstate);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index e74a5185ab0..92931eb8090 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -27,7 +27,7 @@
*/
#include <Python.h>
-#include <float.h> /* FLT_MIN/MAX */
+#include <float.h> /* FLT_MAX */
#include "MEM_guardedalloc.h"
@@ -188,18 +188,19 @@ char pyrna_struct_keyframe_insert_doc[] =
"\n"
" :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
" :type data_path: string\n"
-" :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel "
- "if the property is not an array.\n"
+" :arg index: array index of the property to key.\n"
+" Defaults to -1 which will key all indices or a single channel if the property is not an array.\n"
" :type index: int\n"
" :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n"
" :type frame: float\n"
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
" :type group: str\n"
-" :arg options: Some optional flags:\n"
-" 'NEEDED': Only insert keyframes where they're needed in the relevant F-Curves.\n"
-" 'VISUAL': Insert keyframes based on 'visual transforms'.\n"
-" 'XYZ_TO_RGB': Color for newly added transformation F-Curves (Location, Rotation, Scale) "
- "and also Color is based on the transform axis.\n"
+" :arg options: Optional flags:\n"
+"\n"
+" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant F-Curves.\n"
+" - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n"
+" - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, Rotation, Scale)\n"
+" and also Color is based on the transform axis.\n"
" :type flag: set\n"
" :return: Success of keyframe insertion.\n"
" :rtype: boolean\n"
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index ee827c06e14..2b8ad6ccb90 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -148,4 +148,4 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
bool BPy_errors_to_report(ReportList *reports)
{
return BPy_errors_to_report_ex(reports, true, true);
-} \ No newline at end of file
+}
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index ea5732966b2..71b3cf8ddac 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -1165,9 +1165,9 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle)
{
if (axis) {
if (is_zero_v3(axis) ||
- !finite(axis[0]) ||
- !finite(axis[1]) ||
- !finite(axis[2]))
+ !isfinite(axis[0]) ||
+ !isfinite(axis[1]) ||
+ !isfinite(axis[2]))
{
axis[0] = 1.0f;
axis[1] = 0.0f;
@@ -1182,7 +1182,7 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle)
}
if (angle) {
- if (!finite(*angle)) {
+ if (!isfinite(*angle)) {
*angle = 0.0f;
}
}
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 12b97aedbd3..8b6dfb88b73 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -139,6 +139,7 @@ typedef struct ShadeInput {
float refcol[4], displace[3];
float strandco, tang[3], nmapnorm[3], nmaptang[4], stress, winspeed[4];
float duplilo[3], dupliuv[3];
+ float tangents[8][4]; /* 8 = MAX_MTFACE */
ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */
ShadeInputCol col[8]; /* 8 = MAX_MCOL */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index cef3a073084..6de5da3795a 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -334,6 +334,8 @@ typedef struct ObjectRen {
char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
int actmtface, actmcol, bakemtface;
+ char tangent_mask; /* which tangent layer should be calculated */
+
float obmat[4][4]; /* only used in convertblender.c, for instancing */
/* used on makeraytree */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index 167ebc58030..b576d69d806 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -76,7 +76,7 @@ typedef struct VlakTableNode {
int *origindex;
int totmtface, totmcol;
float *surfnor;
- float *tangent;
+ float *tangent_arrays[MAX_MTFACE];
struct RadFace **radface;
} VlakTableNode;
@@ -137,7 +137,7 @@ struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n,
struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify);
float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
-float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify);
+float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify);
RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
void RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor);
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 00c1129fa85..02a49fc3c8f 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -109,9 +109,9 @@ void rtbuild_add(RTBuilder *b, RayObject *o)
if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
return;
/* skip objects with inf bounding boxes */
- if (!finite(bb[0]) || !finite(bb[1]) || !finite(bb[2]))
+ if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2]))
return;
- if (!finite(bb[3]) || !finite(bb[4]) || !finite(bb[5]))
+ if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5]))
return;
/* skip objects with zero bounding box, they are of no use, and
* will give problems in rtbuild_heuristic_object_split later */
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index b2f8c79c197..31e461b4536 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -926,7 +926,7 @@ static void *do_bake_thread(void *bs_v)
void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
{
/* must check before filtering */
- const short is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
+ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
/* Margin */
if (filter) {
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index eff021c9b14..1a0ef4e64d4 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -425,7 +425,7 @@ static TriTessFace *mesh_calc_tri_tessface(
if (tangent) {
DM_ensure_normals(dm);
- DM_calc_loop_tangents(dm);
+ DM_calc_loop_tangents(dm, true, NULL, 0);
tspace = dm->getLoopDataArray(dm, CD_TANGENT);
BLI_assert(tspace);
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index ccf54cb6bcd..b6ee88de290 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -304,7 +304,7 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
typedef struct {
ObjectRen *obr;
-
+ int mtface_index;
} SRenderMeshToTangent;
/* interface */
@@ -337,7 +337,7 @@ static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->obr->actmtface, NULL, 0);
+ MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
const float *coord;
if (tface != NULL) {
@@ -371,7 +371,7 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
- float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, 1);
+ float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
if (ftang!=NULL) {
copy_v3_v3(&ftang[iVert*4+0], fvTangent);
ftang[iVert*4+3]=fSign;
@@ -457,7 +457,12 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte
sInterface.m_getNormal = GetNormal;
sInterface.m_setTSpaceBasic = SetTSpace;
- genTangSpaceDefault(&sContext);
+ for (a = 0; a < MAX_MTFACE; a++) {
+ if (obr->tangent_mask & 1 << a) {
+ mesh2tangent.mtface_index = a;
+ genTangSpaceDefault(&sContext);
+ }
+ }
}
}
@@ -3113,7 +3118,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
float *orco = NULL;
short (*loop_nors)[4][3] = NULL;
- bool need_orco = false, need_stress = false, need_nmap_tangent = false, need_tangent = false, need_origindex = false;
+ bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
+ bool need_nmap_tangent_concrete = false;
int a, a1, ok, vertofs;
int end, totvert = 0;
bool do_autosmooth = false, do_displace = false;
@@ -3148,9 +3154,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (ma->mode_l & MA_NORMAP_TANG) {
if (me->mtpoly==NULL) {
need_orco= 1;
- need_tangent= 1;
}
- need_nmap_tangent= 1;
+ need_tangent= 1;
+ }
+ if (ma->mode2_l & MA_TANGENT_CONCRETE) {
+ need_nmap_tangent_concrete = true;
}
}
}
@@ -3161,7 +3169,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
need_orco= 1;
need_tangent= 1;
}
- need_nmap_tangent= 1;
+ need_nmap_tangent_concrete = true;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize
@@ -3274,14 +3282,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
- /* add tangent layer if we need one */
- if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
- bool generate_data = false;
- if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
- dm->calcLoopTangents(dm);
- generate_data = true;
- }
- DM_generate_tangent_tessface_data(dm, generate_data);
+ /* add tangent layers if we need */
+ if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
+ dm->calcLoopTangents(
+ dm, need_tangent,
+ (const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
+ obr->tangent_mask = dm->tangent_mask;
+ DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
}
/* still to do for keys: the correct local texture coordinate */
@@ -3401,7 +3408,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
CustomDataLayer *layer;
MTFace *mtface, *mtf;
MCol *mcol, *mc;
- int index, mtfn= 0, mcn= 0, mtng=0, mln = 0, vindex;
+ int index, mtfn= 0, mcn= 0, mln = 0, vindex;
char *name;
int nr_verts = v4!=0 ? 4 : 3;
@@ -3424,17 +3431,24 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
for (vindex=0; vindex<nr_verts; vindex++)
mc[vindex]=mcol[a*4+rev_tab[vindex]];
}
- else if (layer->type == CD_TANGENT && mtng < 1) {
- if (need_nmap_tangent != 0) {
- const float * tangent = (const float *) layer->data;
- float * ftang = RE_vlakren_get_nmap_tangent(obr, vlr, 1);
+ else if (layer->type == CD_TANGENT) {
+ if (need_nmap_tangent_concrete || need_tangent) {
+ int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
+ int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
+ BLI_assert(uv_start >= 0 && uv_index >= 0);
+ if ((uv_start < 0 || uv_index < 0))
+ continue;
+ int n = uv_index - uv_start;
+
+ const float *tangent = (const float *) layer->data;
+ float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
+
for (vindex=0; vindex<nr_verts; vindex++) {
copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
mul_mat3_m4_v3(mat, ftang+vindex*4);
normalize_v3(ftang+vindex*4);
}
}
- mtng++;
}
else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
if (loop_nors) {
@@ -3542,7 +3556,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if (recalc_normals!=0 || need_tangent!=0)
- calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent);
+ calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
}
MEM_SAFE_FREE(loop_nors);
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 8eb6e7000ab..8c6d9c5f951 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -456,7 +456,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t
if (require_tangent) {
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1)
- DM_calc_loop_tangents(dm);
+ DM_calc_loop_tangents(dm, true, NULL, 0);
pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT);
}
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 93666bd2a48..c88e3b36e27 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2860,7 +2860,7 @@ static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportLis
SceneRenderView *srv;
bool active_view = false;
- if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ if (camera == NULL || (scene->r.scemode & R_MULTIVIEW) == 0)
return true;
for (srv = scene->r.views.first; srv; srv = srv->next) {
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 0f77cd9768d..9aac5ed1f1d 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -184,7 +184,7 @@ void freeraytree(Render *re)
#endif
}
-static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
+static bool is_raytraceable_vlr(Render *re, VlakRen *vlr)
{
/* note: volumetric must be tracable, wire must not */
if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
@@ -193,7 +193,7 @@ static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
return 0;
}
-static int is_raytraceable(Render *re, ObjectInstanceRen *obi)
+static bool is_raytraceable(Render *re, ObjectInstanceRen *obi)
{
int v;
ObjectRen *obr = obi->obr;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index e8db096c9a5..d3d26011a57 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -70,6 +70,7 @@
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_texture_types.h"
+#include "DNA_listBase.h"
#include "DNA_particle_types.h"
#include "BKE_customdata.h"
@@ -380,19 +381,28 @@ float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
}
-float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int verify)
+float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
{
- float *tangent;
+ float **tangents;
int nr= vlak->index>>8;
- tangent= obr->vlaknodes[nr].tangent;
- if (tangent==NULL) {
- if (verify)
- tangent= obr->vlaknodes[nr].tangent= MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
+ tangents = obr->vlaknodes[nr].tangent_arrays;
+
+ if (index + 1 > 8) {
+ return NULL;
+ }
+
+ index = index < 0 ? 0: index;
+
+ if (tangents[index] == NULL) {
+ if (verify) {
+ tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
+ }
else
return NULL;
}
- return tangent + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
+
+ return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
}
RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
@@ -415,7 +425,8 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
MTFace *mtface, *mtface1;
MCol *mcol, *mcol1;
- float *surfnor, *surfnor1, *tangent, *tangent1;
+ float *surfnor, *surfnor1;
+ float *tangent, *tangent1;
int *origindex, *origindex1;
RadFace **radface, **radface1;
int i, index = vlr1->index;
@@ -447,9 +458,11 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
copy_v3_v3(surfnor1, surfnor);
}
- tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0);
- if (tangent) {
- tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1);
+ for (i=0; i < MAX_MTFACE; i++) {
+ tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
+ if (!tangent)
+ continue;
+ tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
}
@@ -790,8 +803,10 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes[a].origindex);
if (vlaknodes[a].surfnor)
MEM_freeN(vlaknodes[a].surfnor);
- if (vlaknodes[a].tangent)
- MEM_freeN(vlaknodes[a].tangent);
+ for (int b = 0; b < MAX_MTFACE; b++) {
+ if (vlaknodes[a].tangent_arrays[b])
+ MEM_freeN(vlaknodes[a].tangent_arrays[b]);
+ }
if (vlaknodes[a].radface)
MEM_freeN(vlaknodes[a].radface);
}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index e60a5a70a7f..6e01921a6a7 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -884,7 +884,10 @@ void shade_input_set_shade_texco(ShadeInput *shi)
float u = shi->u, v = shi->v;
float l = 1.0f + u + v, dl;
int mode = shi->mode; /* or-ed result for all nodes */
+ int mode2 = shi->mode2;
short texco = shi->mat->texco;
+ const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
+ const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
/* calculate dxno */
if (shi->vlr->flag & R_SMOOTH) {
@@ -905,8 +908,8 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
/* calc tangents */
- if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
- const float *tangent, *s1, *s2, *s3;
+ if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
+ const float *s1, *s2, *s3;
float tl, tu, tv;
if (shi->vlr->flag & R_SMOOTH) {
@@ -943,14 +946,18 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
- if (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT) {
- tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, 0);
+ if (need_mikk_tangent || need_mikk_tangent_concrete) {
+ int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
+ float c0[3], c1[3], c2[3];
+ int acttang = obr->actmtface;
- if (tangent) {
- int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
- float c0[3], c1[3], c2[3];
+ vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
- vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
+ /* cycle through all tangent in vlakren */
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
+ if (!tangent)
+ continue;
copy_v3_v3(c0, &tangent[j1 * 4]);
copy_v3_v3(c1, &tangent[j2 * 4]);
@@ -966,13 +973,19 @@ void shade_input_set_shade_texco(ShadeInput *shi)
/* we don't normalize the interpolated TBN tangent
* corresponds better to how it's done in game engines */
- shi->nmaptang[0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
- shi->nmaptang[1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
- shi->nmaptang[2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
+ shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
+ shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
+ shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
/* the sign is the same for all 3 vertices of any
* non degenerate triangle. */
- shi->nmaptang[3] = tangent[j1 * 4 + 3];
+ shi->tangents[i][3] = tangent[j1 * 4 + 3];
+
+ if (acttang == i && need_mikk_tangent) {
+ for (int m = 0; m < 4; m++) {
+ shi->nmaptang[m] = shi->tangents[i][m];
+ }
+ }
}
}
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index af8a7cca8dd..01188cb7f65 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -58,6 +58,7 @@ set(SRC
intern/wm_draw.c
intern/wm_event_system.c
intern/wm_files.c
+ intern/wm_files_link.c
intern/wm_gesture.c
intern/wm_init_exit.c
intern/wm_jobs.c
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d9466cbd035..d4c3928bd6c 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -253,7 +253,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
}
/* give it a modal keymap one day? */
-int wm_cursor_arrow_move(wmWindow *win, wmEvent *event)
+bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
if (win && event->val == KM_PRESS) {
if (event->type == UPARROWKEY) {
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index f8a879d0485..8f15d94f538 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -43,7 +43,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_math_base.h"
#include "BIF_gl.h"
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 24d4144ec17..4f9d48450f6 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -410,15 +410,15 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, NULL);
}
-static int wm_event_always_pass(wmEvent *event)
+static int wm_event_always_pass(const wmEvent *event)
{
/* some events we always pass on, to ensure proper communication */
- return ISTIMER(event->type) || (event->type == WINDEACTIVATE) || (event->type == EVT_BUT_OPEN);
+ return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
}
/* ********************* ui handler ******************* */
-static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass)
+static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEvent *event, int always_pass)
{
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -1526,7 +1526,7 @@ int WM_userdef_event_map(int kmitype)
}
-static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
+static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
{
int kmitype = WM_userdef_event_map(kmi->type);
@@ -1921,7 +1921,7 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
return action;
}
-static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
+static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, const wmEvent *event)
{
int action = WM_HANDLER_CONTINUE;
@@ -1933,7 +1933,7 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
return wm_handler_fileselect_do(C, handlers, handler, event->val);
}
-static bool handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
+static bool handler_boundbox_test(wmEventHandler *handler, const wmEvent *event)
{
if (handler->bbwin) {
if (handler->bblocal) {
@@ -2197,12 +2197,6 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect)
return 1;
if (BLI_rcti_isect_pt_v(rect, &event->x))
return 1;
- if (event->type == MOUSEMOVE) {
- if (BLI_rcti_isect_pt_v(rect, &event->prevx)) {
- return 1;
- }
- return 0;
- }
return 0;
}
@@ -2245,7 +2239,7 @@ static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
/* called on mousemove, check updates for paintcursors */
/* context was set on active area and region */
-static void wm_paintcursor_test(bContext *C, wmEvent *event)
+static void wm_paintcursor_test(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2312,7 +2306,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
}
/* filter out all events of the pie that spawned the last pie unless it's a release event */
-static bool wm_event_pie_filter(wmWindow *win, wmEvent *event)
+static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
{
if (win->lock_pie_event && win->lock_pie_event == event->type) {
if (event->val == KM_RELEASE) {
@@ -2365,7 +2359,7 @@ void wm_event_do_handlers(bContext *C)
if (is_playing_sound == 0) {
const float time = BKE_sound_sync_scene(scene);
- if (finite(time)) {
+ if (isfinite(time)) {
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
@@ -2432,7 +2426,6 @@ void wm_event_do_handlers(bContext *C)
if ((action & WM_HANDLER_BREAK) == 0) {
ScrArea *sa;
ARegion *ar;
- int doit = 0;
/* Note: setting subwin active should be done here, after modal handlers have been done */
if (event->type == MOUSEMOVE) {
@@ -2484,8 +2477,6 @@ void wm_event_do_handlers(bContext *C)
if (CTX_wm_window(C) == NULL)
return;
- doit |= (BLI_rcti_isect_pt_v(&ar->winrct, &event->x));
-
if (action & WM_HANDLER_BREAK)
break;
}
@@ -2518,18 +2509,12 @@ void wm_event_do_handlers(bContext *C)
return;
}
- /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad?
- * doing it on ghost queue gives errors when mousemoves go over area borders */
- if (doit && win->screen->subwinactive != win->screen->mainwin) {
- win->eventstate->prevx = event->x;
- win->eventstate->prevy = event->y;
- //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
- }
- else {
- //printf("not setting prev to %d %d\n", event->x, event->y);
- }
}
-
+
+ /* update previous mouse position for following events to use */
+ win->eventstate->prevx = event->x;
+ win->eventstate->prevy = event->y;
+
/* unlink and free here, blender-quit then frees all */
BLI_remlink(&win->queue, event);
wm_event_free(event);
@@ -2912,6 +2897,7 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyQuote: return QUOTEKEY;
case GHOST_kKeyComma: return COMMAKEY;
case GHOST_kKeyMinus: return MINUSKEY;
+ case GHOST_kKeyPlus: return PLUSKEY;
case GHOST_kKeyPeriod: return PERIODKEY;
case GHOST_kKeySlash: return SLASHKEY;
@@ -3124,7 +3110,7 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
return NULL;
}
-static bool wm_event_is_double_click(wmEvent *event, wmEvent *event_state)
+static bool wm_event_is_double_click(wmEvent *event, const wmEvent *event_state)
{
if ((event->type == event_state->prevtype) &&
(event_state->prevval == KM_RELEASE) &&
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index ce722c732e6..36b819d3495 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -26,7 +26,7 @@
/** \file blender/windowmanager/intern/wm_files.c
* \ingroup wm
*
- * User level access for blend file read/write, file-history and userprefs.
+ * User level access for blend file read/write, file-history and userprefs (including relevant operators).
*/
@@ -62,6 +62,7 @@
#include "BLT_translation.h"
+#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
@@ -73,6 +74,8 @@
#include "BKE_utildefines.h"
#include "BKE_autoexec.h"
#include "BKE_blender.h"
+#include "BKE_blendfile.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
@@ -88,6 +91,7 @@
#include "BLO_writefile.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -103,6 +107,7 @@
#include "GHOST_Path-api.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "GPU_draw.h"
@@ -338,7 +343,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
}
@@ -548,7 +553,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* confusing this global... */
G.relbase_valid = 1;
- retval = BKE_read_file(C, filepath, reports);
+ retval = BKE_blendfile_read(C, filepath, reports);
/* when loading startup.blend's, we can be left with a blank path */
if (G.main->name[0]) {
G.save_over = 1;
@@ -569,12 +574,12 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
wm_window_match_do(C, &wmbase);
WM_check(C); /* opens window(s), checks keymaps */
- if (retval == BKE_READ_FILE_OK_USERPREFS) {
+ if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
/* in case a userdef is read from regular .blend */
wm_init_userdef(C, false);
}
- if (retval != BKE_READ_FILE_FAIL) {
+ if (retval != BKE_BLENDFILE_READ_FAIL) {
if (do_history) {
wm_history_file_update();
}
@@ -687,7 +692,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
if (!from_memory) {
if (BLI_access(startstr, R_OK) == 0) {
- success = (BKE_read_file(C, startstr, NULL) != BKE_READ_FILE_FAIL);
+ success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
}
if (BLI_listbase_is_empty(&U.themes)) {
if (G.debug & G_DEBUG)
@@ -702,7 +707,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
}
if (success == 0) {
- success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
+ success = BKE_blendfile_read_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
@@ -717,8 +722,8 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
/* check new prefs only after startup.blend was finished */
if (!from_memory && BLI_exists(prefstr)) {
- int done = BKE_read_file_userdef(prefstr, NULL);
- if (done != BKE_READ_FILE_FAIL) {
+ int done = BKE_blendfile_read_userdef(prefstr, NULL);
+ if (done != BKE_BLENDFILE_READ_FAIL) {
read_userdef_from_memory = false;
printf("Read new prefs: %s\n", prefstr);
}
@@ -749,44 +754,6 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
return true;
}
-int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- ED_file_read_bookmarks();
- wm_history_file_read();
- return OPERATOR_FINISHED;
-}
-
-int wm_homefile_read_exec(bContext *C, wmOperator *op)
-{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
- char filepath_buf[FILE_MAX];
- const char *filepath = NULL;
-
- if (!from_memory) {
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
-
- /* This can be used when loading of a start-up file should only change
- * the scene content but keep the blender UI as it is. */
- wm_open_init_load_ui(op, true);
- BKE_BIT_TEST_SET(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
-
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_string_get(op->ptr, prop, filepath_buf);
- filepath = filepath_buf;
- if (BLI_access(filepath, R_OK)) {
- BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
- return OPERATOR_CANCELLED;
- }
- }
- }
- else {
- /* always load UI for factory settings (prefs will re-init) */
- G.fileflags &= ~G_FILE_NO_UI;
- }
-
- return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
/** \name WM History File API
* \{ */
@@ -1005,7 +972,7 @@ bool write_crash_blend(void)
/**
* \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way.
*/
-int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
+static int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
{
Library *li;
int len;
@@ -1117,69 +1084,6 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
return ret;
}
-/**
- * \see #wm_file_write wraps #BLO_write_file in a similar way.
- */
-int wm_homefile_write_exec(bContext *C, wmOperator *op)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- char filepath[FILE_MAX];
- int fileflags;
-
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
-
- /* check current window and close it if temp */
- if (win && win->screen->temp)
- wm_window_close(C, wm, win);
-
- /* update keymaps in user preferences */
- WM_keyconfig_update(wm);
-
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
- printf("trying to save homefile at %s ", filepath);
-
- ED_editors_flush_edits(C, false);
-
- /* force save as regular blend file */
- fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
-
- if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
- }
-
- printf("ok\n");
-
- G.save_over = 0;
-
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
-
- return OPERATOR_FINISHED;
-}
-
-/* Only save the prefs block. operator entry */
-int wm_userpref_write_exec(bContext *C, wmOperator *op)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- char filepath[FILE_MAX];
-
- /* update keymaps in user preferences */
- WM_keyconfig_update(wm);
-
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_write_file_userdef(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
- }
-
- printf("ok\n");
-
- return OPERATOR_FINISHED;
-}
-
/************************ autosave ****************************/
void wm_autosave_location(char *filepath)
@@ -1341,3 +1245,730 @@ void WM_file_tag_modified(const bContext *C)
WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
}
}
+
+/** \name Preferences/startup save & load.
+ *
+ * \{ */
+
+/**
+ * \see #wm_file_write wraps #BLO_write_file in a similar way.
+ */
+static int wm_homefile_write_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ char filepath[FILE_MAX];
+ int fileflags;
+
+ BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
+
+ /* check current window and close it if temp */
+ if (win && win->screen->temp)
+ wm_window_close(C, wm, win);
+
+ /* update keymaps in user preferences */
+ WM_keyconfig_update(wm);
+
+ BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ printf("trying to save homefile at %s ", filepath);
+
+ ED_editors_flush_edits(C, false);
+
+ /* force save as regular blend file */
+ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+
+ if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
+ printf("fail\n");
+ return OPERATOR_CANCELLED;
+ }
+
+ printf("ok\n");
+
+ G.save_over = 0;
+
+ BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_save_homefile(wmOperatorType *ot)
+{
+ ot->name = "Save Startup File";
+ ot->idname = "WM_OT_save_homefile";
+ ot->description = "Make the current file the default .blend file, includes preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_write_exec;
+}
+
+static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
+ BLI_addtail(&U.autoexec_paths, path_cmp);
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
+{
+ ot->name = "Add Autoexec Path";
+ ot->idname = "WM_OT_userpref_autoexec_path_add";
+ ot->description = "Add path to exclude from autoexecution";
+
+ ot->exec = wm_userpref_autoexec_add_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
+{
+ const int index = RNA_int_get(op->ptr, "index");
+ bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
+ if (path_cmp) {
+ BLI_freelinkN(&U.autoexec_paths, path_cmp);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Autoexec Path";
+ ot->idname = "WM_OT_userpref_autoexec_path_remove";
+ ot->description = "Remove path to exclude from autoexecution";
+
+ ot->exec = wm_userpref_autoexec_remove_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
+}
+
+/* Only save the prefs block. operator entry */
+static int wm_userpref_write_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ char filepath[FILE_MAX];
+
+ /* update keymaps in user preferences */
+ WM_keyconfig_update(wm);
+
+ BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
+ printf("trying to save userpref at %s ", filepath);
+
+ if (BKE_blendfile_write_userdef(filepath, op->reports) == 0) {
+ printf("fail\n");
+ return OPERATOR_CANCELLED;
+ }
+
+ printf("ok\n");
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_save_userpref(wmOperatorType *ot)
+{
+ ot->name = "Save User Settings";
+ ot->idname = "WM_OT_save_userpref";
+ ot->description = "Save user preferences separately, overrides startup file preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_userpref_write_exec;
+}
+
+static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ ED_file_read_bookmarks();
+ wm_history_file_read();
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_read_history(wmOperatorType *ot)
+{
+ ot->name = "Reload History File";
+ ot->idname = "WM_OT_read_history";
+ ot->description = "Reloads history and bookmarks";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_history_file_read_exec;
+
+ /* this operator is only used for loading settings from a previous blender install */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+static int wm_homefile_read_exec(bContext *C, wmOperator *op)
+{
+ const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ char filepath_buf[FILE_MAX];
+ const char *filepath = NULL;
+
+ if (!from_memory) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
+
+ /* This can be used when loading of a start-up file should only change
+ * the scene content but keep the blender UI as it is. */
+ wm_open_init_load_ui(op, true);
+ BKE_BIT_TEST_SET(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
+
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_string_get(op->ptr, prop, filepath_buf);
+ filepath = filepath_buf;
+ if (BLI_access(filepath, R_OK)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ else {
+ /* always load UI for factory settings (prefs will re-init) */
+ G.fileflags &= ~G_FILE_NO_UI;
+ }
+
+ return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void WM_OT_read_homefile(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ ot->name = "Reload Start-Up File";
+ ot->idname = "WM_OT_read_homefile";
+ ot->description = "Open the default file (doesn't save the current file)";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
+ FILE_MAX, "File Path",
+ "Path to an alternative start-up file");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* So scripts can use an alternative start-up file without the UI */
+ prop = RNA_def_boolean(ot->srna, "load_ui", true, "Load UI",
+ "Load user interface setup from the .blend file");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* omit poll to run in background mode */
+}
+
+void WM_OT_read_factory_settings(wmOperatorType *ot)
+{
+ ot->name = "Load Factory Settings";
+ ot->idname = "WM_OT_read_factory_settings";
+ ot->description = "Load default file and user preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_read_exec;
+ /* omit poll to run in background mode */
+}
+
+/** \} */
+
+/** \name Open main .blend file.
+ *
+ * \{ */
+
+/**
+ * Wrap #WM_file_read, shared by file reading operators.
+ */
+static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports,
+ const bool autoexec_init)
+{
+ bool success;
+
+ /* XXX wm in context is not set correctly after WM_file_read -> crash */
+ /* do it before for now, but is this correct with multiple windows? */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ if (autoexec_init) {
+ WM_file_autoexec_init(filepath);
+ }
+
+ success = WM_file_read(C, filepath, reports);
+
+ return success;
+}
+
+/* currently fits in a pointer */
+struct FileRuntime {
+ bool is_untrusted;
+};
+
+static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const char *openname = G.main->name;
+
+ if (CTX_wm_window(C) == NULL) {
+ /* in rare cases this could happen, when trying to invoke in background
+ * mode on load for example. Don't use poll for this because exec()
+ * can still run without a window */
+ BKE_report(op->reports, RPT_ERROR, "Context window not set");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if possible, get the name of the most recently used .blend file */
+ if (G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ openname = recent->filepath;
+ }
+
+ RNA_string_set(op->ptr, "filepath", openname);
+ wm_open_init_load_ui(op, true);
+ wm_open_init_use_scripts(op, true);
+ op->customdata = NULL;
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ bool success;
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ /* re-use last loaded setting so we can reload a file without changing */
+ wm_open_init_load_ui(op, false);
+ wm_open_init_use_scripts(op, false);
+
+ if (RNA_boolean_get(op->ptr, "load_ui"))
+ G.fileflags &= ~G_FILE_NO_UI;
+ else
+ G.fileflags |= G_FILE_NO_UI;
+
+ if (RNA_boolean_get(op->ptr, "use_scripts"))
+ G.f |= G_SCRIPT_AUTOEXEC;
+ else
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+
+ success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
+
+ /* for file open also popup for warnings, not only errors */
+ BKE_report_print_level_set(op->reports, RPT_WARNING);
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
+{
+ struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
+ bool is_untrusted = false;
+ char path[FILE_MAX];
+ char *lslash;
+
+ RNA_string_get(op->ptr, "filepath", path);
+
+ /* get the dir */
+ lslash = (char *)BLI_last_slash(path);
+ if (lslash) *(lslash + 1) = '\0';
+
+ if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
+ if (BKE_autoexec_match(path) == true) {
+ RNA_property_boolean_set(op->ptr, prop, false);
+ is_untrusted = true;
+ }
+ }
+
+ if (file_info) {
+ file_info->is_untrusted = is_untrusted;
+ }
+
+ return is_untrusted;
+}
+
+static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
+ uiLayout *layout = op->layout;
+ uiLayout *col = op->layout;
+ const char *autoexec_text;
+
+ uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ if (file_info->is_untrusted) {
+ autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
+ uiLayoutSetActive(col, false);
+ uiLayoutSetEnabled(col, false);
+ }
+ else {
+ autoexec_text = IFACE_("Trusted Source");
+ }
+
+ uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
+}
+
+void WM_OT_open_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Open Blender File";
+ ot->idname = "WM_OT_open_mainfile";
+ ot->description = "Open a Blender file";
+
+ ot->invoke = wm_open_mainfile_invoke;
+ ot->exec = wm_open_mainfile_exec;
+ ot->check = wm_open_mainfile_check;
+ ot->ui = wm_open_mainfile_ui;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
+ "Allow .blend file to execute scripts automatically, default available from system preferences");
+}
+
+/** \} */
+
+/** \name Reload (revert) main .blend file.
+ *
+ * \{ */
+
+static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
+{
+ bool success;
+ char filepath[FILE_MAX];
+
+ wm_open_init_use_scripts(op, false);
+
+ if (RNA_boolean_get(op->ptr, "use_scripts"))
+ G.f |= G_SCRIPT_AUTOEXEC;
+ else
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+
+ BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int wm_revert_mainfile_poll(bContext *UNUSED(C))
+{
+ return G.relbase_valid;
+}
+
+void WM_OT_revert_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Revert";
+ ot->idname = "WM_OT_revert_mainfile";
+ ot->description = "Reload the saved file";
+ ot->invoke = WM_operator_confirm;
+
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
+ "Allow .blend file to execute scripts automatically, default available from system preferences");
+
+ ot->exec = wm_revert_mainfile_exec;
+ ot->poll = wm_revert_mainfile_poll;
+}
+
+/** \} */
+
+/** \name Recover last session & auto-save.
+ *
+ * \{ */
+
+void WM_recover_last_session(bContext *C, ReportList *reports)
+{
+ char filepath[FILE_MAX];
+
+ BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ /* if reports==NULL, it's called directly without operator, we add a quick check here */
+ if (reports || BLI_exists(filepath)) {
+ G.fileflags |= G_FILE_RECOVER;
+
+ wm_file_read_opwrap(C, filepath, reports, true);
+
+ G.fileflags &= ~G_FILE_RECOVER;
+
+ /* XXX bad global... fixme */
+ if (G.main->name[0])
+ G.file_loaded = 1; /* prevents splash to show */
+ else {
+ G.relbase_valid = 0;
+ G.save_over = 0; /* start with save preference untitled.blend */
+ }
+
+ }
+}
+
+static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
+{
+ WM_recover_last_session(C, op->reports);
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_recover_last_session(wmOperatorType *ot)
+{
+ ot->name = "Recover Last Session";
+ ot->idname = "WM_OT_recover_last_session";
+ ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
+ ot->invoke = WM_operator_confirm;
+
+ ot->exec = wm_recover_last_session_exec;
+}
+
+static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ bool success;
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ G.fileflags |= G_FILE_RECOVER;
+
+ success = wm_file_read_opwrap(C, filepath, op->reports, true);
+
+ G.fileflags &= ~G_FILE_RECOVER;
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ char filename[FILE_MAX];
+
+ wm_autosave_location(filename);
+ RNA_string_set(op->ptr, "filepath", filename);
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void WM_OT_recover_auto_save(wmOperatorType *ot)
+{
+ ot->name = "Recover Auto Save";
+ ot->idname = "WM_OT_recover_auto_save";
+ ot->description = "Open an automatically saved file to recover it";
+
+ ot->exec = wm_recover_auto_save_exec;
+ ot->invoke = wm_recover_auto_save_invoke;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
+}
+
+/** \} */
+
+/** \name Save main .blend file.
+ *
+ * \{ */
+
+static void wm_filepath_default(char *filepath)
+{
+ if (G.save_over == false) {
+ BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
+ }
+}
+
+static void save_set_compress(wmOperator *op)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "compress");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ if (G.save_over) { /* keep flag for existing file */
+ RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
+ }
+ else { /* use userdef for new file */
+ RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
+ }
+ }
+}
+
+static void save_set_filepath(wmOperator *op)
+{
+ PropertyRNA *prop;
+ char name[FILE_MAX];
+
+ prop = RNA_struct_find_property(op->ptr, "filepath");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* if not saved before, get the name of the most recently used .blend file */
+ if (G.main->name[0] == 0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+ }
+
+ wm_filepath_default(name);
+ RNA_property_string_set(op->ptr, prop, name);
+ }
+}
+
+static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+
+ save_set_compress(op);
+ save_set_filepath(op);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* function used for WM_OT_save_mainfile too */
+static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
+{
+ char path[FILE_MAX];
+ int fileflags;
+
+ save_set_compress(op);
+
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_get(op->ptr, "filepath", path);
+ }
+ else {
+ BLI_strncpy(path, G.main->name, FILE_MAX);
+ wm_filepath_default(path);
+ }
+
+ fileflags = G.fileflags & ~G_FILE_USERPREFS;
+
+ /* set compression flag */
+ BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
+ G_FILE_COMPRESS);
+ BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
+ G_FILE_RELATIVE_REMAP);
+ BKE_BIT_TEST_SET(fileflags,
+ (RNA_struct_property_is_set(op->ptr, "copy") &&
+ RNA_boolean_get(op->ptr, "copy")),
+ G_FILE_SAVE_COPY);
+
+#ifdef USE_BMESH_SAVE_AS_COMPAT
+ BKE_BIT_TEST_SET(fileflags,
+ (RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
+ RNA_boolean_get(op->ptr, "use_mesh_compat")),
+ G_FILE_MESH_COMPAT);
+#else
+# error "don't remove by accident"
+#endif
+
+ if (wm_file_write(C, path, fileflags, op->reports) != 0)
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/* function used for WM_OT_save_mainfile too */
+static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ if (!BLO_has_bfile_extension(filepath)) {
+ /* some users would prefer BLI_replace_extension(),
+ * we keep getting nitpicking bug reports about this - campbell */
+ BLI_ensure_extension(filepath, FILE_MAX, ".blend");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+ return false;
+}
+
+void WM_OT_save_as_mainfile(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Save As Blender File";
+ ot->idname = "WM_OT_save_as_mainfile";
+ ot->description = "Save the current file in the desired location";
+
+ ot->invoke = wm_save_as_mainfile_invoke;
+ ot->exec = wm_save_as_mainfile_exec;
+ ot->check = blend_save_check;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
+ RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
+ "Remap relative paths when saving in a different directory");
+ prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
+ "Save a copy of the actual working state but does not make saved file active");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+#ifdef USE_BMESH_SAVE_AS_COMPAT
+ RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
+ "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
+ "be lost (no implicit triangulation)");
+#endif
+}
+
+static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ int ret;
+
+ /* cancel if no active window */
+ if (CTX_wm_window(C) == NULL)
+ return OPERATOR_CANCELLED;
+
+ save_set_compress(op);
+ save_set_filepath(op);
+
+ /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
+ * enable the option to remap paths to avoid confusion [#37240] */
+ if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, true);
+ }
+ }
+
+ if (G.save_over) {
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ if (BLI_exists(path)) {
+ ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
+ }
+ else {
+ ret = wm_save_as_mainfile_exec(C, op);
+ }
+ }
+ else {
+ WM_event_add_fileselect(C, op);
+ ret = OPERATOR_RUNNING_MODAL;
+ }
+
+ return ret;
+}
+
+void WM_OT_save_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Save Blender File";
+ ot->idname = "WM_OT_save_mainfile";
+ ot->description = "Save the current Blender file";
+
+ ot->invoke = wm_save_mainfile_invoke;
+ ot->exec = wm_save_as_mainfile_exec;
+ ot->check = blend_save_check;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
+ RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
+ "Remap relative paths when saving in a different directory");
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
new file mode 100644
index 00000000000..2e4a4b63b7a
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -0,0 +1,520 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_files_link.c
+ * \ingroup wm
+ *
+ * Functions for dealing with append/link operators and helpers.
+ */
+
+
+#include <float.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+
+
+
+#include "BLI_blenlib.h"
+#include "BLI_bitmap.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BLO_readfile.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "BKE_idcode.h"
+
+
+#include "IMB_colormanagement.h"
+
+#include "ED_screen.h"
+
+#include "GPU_material.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_files.h"
+
+/* **************** link/append *************** */
+
+static int wm_link_append_poll(bContext *C)
+{
+ if (WM_operator_winactive(C)) {
+ /* linking changes active object which is pretty useful in general,
+ * but which totally confuses edit mode (i.e. it becoming not so obvious
+ * to leave from edit mode and invalid tools in toolbar might be displayed)
+ * so disable link/append when in edit mode (sergey) */
+ if (CTX_data_edit_object(C))
+ return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ return WM_operator_call_notest(C, op);
+ }
+ else {
+ /* XXX TODO solve where to get last linked library from */
+ if (G.lib[0] != '\0') {
+ RNA_string_set(op->ptr, "filepath", G.lib);
+ }
+ else if (G.relbase_valid) {
+ char path[FILE_MAX];
+ BLI_strncpy(path, G.main->name, sizeof(G.main->name));
+ BLI_parent_dir(path);
+ RNA_string_set(op->ptr, "filepath", path);
+ }
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+ }
+}
+
+static short wm_link_append_flag(wmOperator *op)
+{
+ PropertyRNA *prop;
+ short flag = 0;
+
+ if (RNA_boolean_get(op->ptr, "autoselect"))
+ flag |= FILE_AUTOSELECT;
+ if (RNA_boolean_get(op->ptr, "active_layer"))
+ flag |= FILE_ACTIVELAY;
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
+ flag |= FILE_RELPATH;
+ if (RNA_boolean_get(op->ptr, "link"))
+ flag |= FILE_LINK;
+ if (RNA_boolean_get(op->ptr, "instance_groups"))
+ flag |= FILE_GROUP_INSTANCE;
+
+ return flag;
+}
+
+typedef struct WMLinkAppendDataItem {
+ char *name;
+ BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
+ short idcode;
+
+ ID *new_id;
+ void *customdata;
+} WMLinkAppendDataItem;
+
+typedef struct WMLinkAppendData {
+ LinkNodePair libraries;
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ short flag;
+
+ /* Internal 'private' data */
+ MemArena *memarena;
+} WMLinkAppendData;
+
+static WMLinkAppendData *wm_link_append_data_new(const int flag)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
+
+ lapp_data->flag = flag;
+ lapp_data->memarena = ma;
+
+ return lapp_data;
+}
+
+static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
+{
+ BLI_memarena_free(lapp_data->memarena);
+}
+
+/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
+
+static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
+{
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
+
+ BLI_strncpy(libpath, libname, len);
+ BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
+ lapp_data->num_libraries++;
+}
+
+static WMLinkAppendDataItem *wm_link_append_data_item_add(
+ WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata)
+{
+ WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_data->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
+
+ item->new_id = NULL;
+ item->customdata = customdata;
+
+ BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
+ lapp_data->num_items++;
+
+ return item;
+}
+
+static void wm_link_do(
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+{
+ Main *mainl;
+ BlendHandle *bh;
+ Library *lib;
+
+ const int flag = lapp_data->flag;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
+
+ for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
+ char *libname = liblink->link;
+
+ bh = BLO_blendhandle_from_file(libname, reports);
+
+ if (bh == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile, mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ if (new_id) {
+ /* If the link is sucessful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
+ item->new_id = new_id;
+ }
+ }
+
+ BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_blendhandle_close(bh);
+ }
+}
+
+static int wm_link_append_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
+ WMLinkAppendData *lapp_data;
+ char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ char *group, *name;
+ int totfiles = 0;
+ short flag;
+
+ RNA_string_get(op->ptr, "filename", relname);
+ RNA_string_get(op->ptr, "directory", root);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ /* test if we have a valid data */
+ if (!BLO_library_path_explode(path, libname, &group, &name)) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
+ return OPERATOR_CANCELLED;
+ }
+ else if (!group) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+ else if (BLI_path_cmp(bmain->name, libname) == 0) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* check if something is indicated for append/link */
+ prop = RNA_struct_find_property(op->ptr, "files");
+ if (prop) {
+ totfiles = RNA_property_collection_length(op->ptr, prop);
+ if (totfiles == 0) {
+ if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ else if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+
+ flag = wm_link_append_flag(op);
+
+ /* sanity checks for flag */
+ if (scene && scene->id.lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2);
+ flag &= ~FILE_GROUP_INSTANCE;
+ scene = NULL;
+ }
+
+ /* from here down, no error returns */
+
+ if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_scene_base_deselect_all(scene);
+ }
+
+ /* tag everything, all untagged data can be made local
+ * its also generally useful to know what is new
+ *
+ * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We define our working data...
+ * Note that here, each item 'uses' one library, and only one. */
+ lapp_data = wm_link_append_data_new(flag);
+ if (totfiles != 0) {
+ GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+ int lib_idx = 0;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ if (!group || !name) {
+ continue;
+ }
+
+ if (!BLI_ghash_haskey(libraries, libname)) {
+ BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
+ lib_idx++;
+ wm_link_append_data_library_add(lapp_data, libname);
+ }
+ }
+ }
+ RNA_END;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ WMLinkAppendDataItem *item;
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ continue;
+ }
+
+ lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
+
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ }
+ }
+ RNA_END;
+
+ BLI_ghash_free(libraries, MEM_freeN, NULL);
+ }
+ else {
+ WMLinkAppendDataItem *item;
+
+ wm_link_append_data_library_add(lapp_data, libname);
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, 0);
+ }
+
+ /* XXX We'd need re-entrant locking on Main for this to work... */
+ /* BKE_main_lock(bmain); */
+
+ wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+
+ /* BKE_main_unlock(bmain); */
+
+ /* mark all library linked objects to be updated */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* append, rather than linking */
+ if ((flag & FILE_LINK) == 0) {
+ const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
+ const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
+
+ if (use_recursive) {
+ BKE_library_make_local(bmain, NULL, true, set_fake);
+ }
+ else {
+ LinkNode *itemlink;
+ GSet *done_libraries = BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp,
+ __func__, lapp_data->num_libraries);
+
+ for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
+ ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id;
+
+ if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) {
+ BKE_library_make_local(bmain, new_id->lib, true, set_fake);
+ BLI_gset_insert(done_libraries, new_id->lib);
+ }
+ }
+
+ BLI_gset_free(done_libraries, NULL);
+ }
+ }
+
+ wm_link_append_data_free(lapp_data);
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
+ BLI_strncpy(G.lib, root, FILE_MAX);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
+{
+ PropertyRNA *prop;
+
+ /* better not save _any_ settings for this operator */
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "link", is_link,
+ "Link", "Link the objects or datablocks rather than appending");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "autoselect", true,
+ "Select", "Select new objects");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "active_layer", true,
+ "Active Layer", "Put new objects on the active layer");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
+ "Instance Groups", "Create Dupli-Group instances for each group");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+void WM_OT_link(wmOperatorType *ot)
+{
+ ot->name = "Link from Library";
+ ot->idname = "WM_OT_link";
+ ot->description = "Link from a Library .blend file";
+
+ ot->invoke = wm_link_append_invoke;
+ ot->exec = wm_link_append_exec;
+ ot->poll = wm_link_append_poll;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ wm_link_append_properties_common(ot, true);
+}
+
+void WM_OT_append(wmOperatorType *ot)
+{
+ ot->name = "Append from Library";
+ ot->idname = "WM_OT_append";
+ ot->description = "Append from a Library .blend file";
+
+ ot->invoke = wm_link_append_invoke;
+ ot->exec = wm_link_append_exec;
+ ot->poll = wm_link_append_poll;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ wm_link_append_properties_common(ot, false);
+ RNA_def_boolean(ot->srna, "set_fake", false, "Fake User",
+ "Set Fake User for appended items (except Objects and Groups)");
+ RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All",
+ "Localize all appended data, including those indirectly linked from other libraries");
+}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 4dc60a9b729..6300d2ed3c7 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -54,6 +54,7 @@
#include "BLO_writefile.h"
#include "BKE_blender.h"
+#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_DerivedMesh.h"
@@ -97,9 +98,11 @@
#include "wm_files.h"
#include "wm_window.h"
+#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
#include "ED_node.h"
#include "ED_render.h"
#include "ED_space_api.h"
@@ -399,13 +402,6 @@ static void free_openrecent(void)
}
-/* bad stuff*/
-
-// XXX copy/paste buffer stuff...
-extern void free_anim_copybuf(void);
-extern void free_anim_drivers_copybuf(void);
-extern void free_fmodifiers_copybuf(void);
-
#ifdef WIN32
/* Read console events until there is a key event. Also returns on any error. */
static void wait_for_console_key(void)
@@ -497,10 +493,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
RE_FreeAllRender();
RE_engines_exit();
- ED_preview_free_dbase(); /* frees a Main dbase, before free_blender! */
+ ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
if (C && wm)
- wm_free_reports(C); /* before free_blender! - since the ListBases get freed there */
+ wm_free_reports(C); /* before BKE_blender_free! - since the ListBases get freed there */
BKE_sequencer_free_clipboard(); /* sequencer.c */
BKE_tracking_clipboard_free();
@@ -511,11 +507,12 @@ void WM_exit_ext(bContext *C, const bool do_python)
COM_deinitialize();
#endif
- free_blender(); /* blender.c, does entire library and spacetypes */
+ BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
- free_anim_copybuf();
- free_anim_drivers_copybuf();
- free_fmodifiers_copybuf();
+ ANIM_fcurves_copybuf_free();
+ ANIM_drivers_copybuf_free();
+ ANIM_driver_vars_copybuf_free();
+ ANIM_fmodifiers_copybuf_free();
ED_gpencil_anim_copybuf_free();
ED_gpencil_strokes_copybuf_free();
ED_clipboard_posebuf_free();
@@ -538,10 +535,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
/* option not to close python so we can use 'atexit' */
if (do_python) {
/* XXX - old note */
- /* before free_blender so py's gc happens while library still exists */
+ /* before BKE_blender_free so py's gc happens while library still exists */
/* needed at least for a rare sigsegv that can happen in pydrivers */
- /* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's
+ /* Update for blender 2.5, move after BKE_blender_free because blender now holds references to PyObject's
* so decref'ing them after python ends causes bad problems every time
* the pyDriver bug can be fixed if it happens again we can deal with it then */
BPY_python_end();
@@ -566,7 +563,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_file_exit(); /* for fsmenu */
UI_exit();
- BKE_userdef_free();
+ BKE_blender_userdef_free();
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b5ad027148a..6ef8965a408 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -52,27 +52,22 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
#include "BLT_translation.h"
#include "PIL_time.h"
#include "BLI_blenlib.h"
-#include "BLI_bitmap.h"
#include "BLI_dial.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
-#include "BLI_linklist.h"
#include "BLI_math.h"
-#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLO_readfile.h"
#include "BKE_appdir.h"
-#include "BKE_autoexec.h"
-#include "BKE_blender.h"
+#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -88,14 +83,12 @@
#include "BKE_scene.h"
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
#include "BKE_unit.h"
-#include "BKE_utildefines.h"
#include "BKE_idcode.h"
#include "BIF_glutil.h" /* for paint cursor */
#include "BLF_api.h"
-#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -105,7 +98,6 @@
#include "ED_view3d.h"
#include "GPU_basic_shader.h"
-#include "GPU_material.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -2073,1025 +2065,6 @@ static void WM_OT_window_duplicate(wmOperatorType *ot)
ot->poll = wm_operator_winactive_normal;
}
-static void WM_OT_save_homefile(wmOperatorType *ot)
-{
- ot->name = "Save Startup File";
- ot->idname = "WM_OT_save_homefile";
- ot->description = "Make the current file the default .blend file, includes preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_write_exec;
-}
-
-static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
- BLI_addtail(&U.autoexec_paths, path_cmp);
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
-{
- ot->name = "Add Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_add";
- ot->description = "Add path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_add_exec;
-
- ot->flag = OPTYPE_INTERNAL;
-}
-
-static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
-{
- const int index = RNA_int_get(op->ptr, "index");
- bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
- if (path_cmp) {
- BLI_freelinkN(&U.autoexec_paths, path_cmp);
- }
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_remove";
- ot->description = "Remove path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_remove_exec;
-
- ot->flag = OPTYPE_INTERNAL;
-
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
-}
-
-static void WM_OT_save_userpref(wmOperatorType *ot)
-{
- ot->name = "Save User Settings";
- ot->idname = "WM_OT_save_userpref";
- ot->description = "Save user preferences separately, overrides startup file preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_userpref_write_exec;
-}
-
-static void WM_OT_read_history(wmOperatorType *ot)
-{
- ot->name = "Reload History File";
- ot->idname = "WM_OT_read_history";
- ot->description = "Reloads history and bookmarks";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_history_file_read_exec;
-
- /* this operator is only used for loading settings from a previous blender install */
- ot->flag = OPTYPE_INTERNAL;
-}
-
-static void WM_OT_read_homefile(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- ot->name = "Reload Start-Up File";
- ot->idname = "WM_OT_read_homefile";
- ot->description = "Open the default file (doesn't save the current file)";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_read_exec;
-
- prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
- FILE_MAX, "File Path",
- "Path to an alternative start-up file");
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- /* So scripts can use an alternative start-up file without the UI */
- prop = RNA_def_boolean(ot->srna, "load_ui", true, "Load UI",
- "Load user interface setup from the .blend file");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- /* omit poll to run in background mode */
-}
-
-static void WM_OT_read_factory_settings(wmOperatorType *ot)
-{
- ot->name = "Load Factory Settings";
- ot->idname = "WM_OT_read_factory_settings";
- ot->description = "Load default file and user preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_read_exec;
- /* omit poll to run in background mode */
-}
-
-/* *************** open file **************** */
-
-/**
- * Wrap #WM_file_read, shared by file reading operators.
- */
-static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports,
- const bool autoexec_init)
-{
- bool success;
-
- /* XXX wm in context is not set correctly after WM_file_read -> crash */
- /* do it before for now, but is this correct with multiple windows? */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
- if (autoexec_init) {
- WM_file_autoexec_init(filepath);
- }
-
- success = WM_file_read(C, filepath, reports);
-
- return success;
-}
-
-/* currently fits in a pointer */
-struct FileRuntime {
- bool is_untrusted;
-};
-
-static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- const char *openname = G.main->name;
-
- if (CTX_wm_window(C) == NULL) {
- /* in rare cases this could happen, when trying to invoke in background
- * mode on load for example. Don't use poll for this because exec()
- * can still run without a window */
- BKE_report(op->reports, RPT_ERROR, "Context window not set");
- return OPERATOR_CANCELLED;
- }
-
- /* if possible, get the name of the most recently used .blend file */
- if (G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- openname = recent->filepath;
- }
-
- RNA_string_set(op->ptr, "filepath", openname);
- wm_open_init_load_ui(op, true);
- wm_open_init_use_scripts(op, true);
- op->customdata = NULL;
-
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
-{
- char filepath[FILE_MAX];
- bool success;
-
- RNA_string_get(op->ptr, "filepath", filepath);
-
- /* re-use last loaded setting so we can reload a file without changing */
- wm_open_init_load_ui(op, false);
- wm_open_init_use_scripts(op, false);
-
- if (RNA_boolean_get(op->ptr, "load_ui"))
- G.fileflags &= ~G_FILE_NO_UI;
- else
- G.fileflags |= G_FILE_NO_UI;
-
- if (RNA_boolean_get(op->ptr, "use_scripts"))
- G.f |= G_SCRIPT_AUTOEXEC;
- else
- G.f &= ~G_SCRIPT_AUTOEXEC;
-
- success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
-
- /* for file open also popup for warnings, not only errors */
- BKE_report_print_level_set(op->reports, RPT_WARNING);
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
-{
- struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
- bool is_untrusted = false;
- char path[FILE_MAX];
- char *lslash;
-
- RNA_string_get(op->ptr, "filepath", path);
-
- /* get the dir */
- lslash = (char *)BLI_last_slash(path);
- if (lslash) *(lslash + 1) = '\0';
-
- if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
- if (BKE_autoexec_match(path) == true) {
- RNA_property_boolean_set(op->ptr, prop, false);
- is_untrusted = true;
- }
- }
-
- if (file_info) {
- file_info->is_untrusted = is_untrusted;
- }
-
- return is_untrusted;
-}
-
-static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
-{
- struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
- uiLayout *layout = op->layout;
- uiLayout *col = op->layout;
- const char *autoexec_text;
-
- uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- if (file_info->is_untrusted) {
- autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
- uiLayoutSetActive(col, false);
- uiLayoutSetEnabled(col, false);
- }
- else {
- autoexec_text = IFACE_("Trusted Source");
- }
-
- uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
-}
-
-static void WM_OT_open_mainfile(wmOperatorType *ot)
-{
- ot->name = "Open Blender File";
- ot->idname = "WM_OT_open_mainfile";
- ot->description = "Open a Blender file";
-
- ot->invoke = wm_open_mainfile_invoke;
- ot->exec = wm_open_mainfile_exec;
- ot->check = wm_open_mainfile_check;
- ot->ui = wm_open_mainfile_ui;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
- RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
- "Allow .blend file to execute scripts automatically, default available from system preferences");
-}
-
-
-/* *************** revert file **************** */
-
-static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
-{
- bool success;
-
- wm_open_init_use_scripts(op, false);
-
- if (RNA_boolean_get(op->ptr, "use_scripts"))
- G.f |= G_SCRIPT_AUTOEXEC;
- else
- G.f &= ~G_SCRIPT_AUTOEXEC;
-
- success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int wm_revert_mainfile_poll(bContext *UNUSED(C))
-{
- return G.relbase_valid;
-}
-
-static void WM_OT_revert_mainfile(wmOperatorType *ot)
-{
- ot->name = "Revert";
- ot->idname = "WM_OT_revert_mainfile";
- ot->description = "Reload the saved file";
- ot->invoke = WM_operator_confirm;
-
- RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
- "Allow .blend file to execute scripts automatically, default available from system preferences");
-
- ot->exec = wm_revert_mainfile_exec;
- ot->poll = wm_revert_mainfile_poll;
-}
-
-/* **************** link/append *************** */
-
-static int wm_link_append_poll(bContext *C)
-{
- if (WM_operator_winactive(C)) {
- /* linking changes active object which is pretty useful in general,
- * but which totally confuses edit mode (i.e. it becoming not so obvious
- * to leave from edit mode and invalid tools in toolbar might be displayed)
- * so disable link/append when in edit mode (sergey) */
- if (CTX_data_edit_object(C))
- return 0;
-
- return 1;
- }
-
- return 0;
-}
-
-static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- return WM_operator_call_notest(C, op);
- }
- else {
- /* XXX TODO solve where to get last linked library from */
- if (G.lib[0] != '\0') {
- RNA_string_set(op->ptr, "filepath", G.lib);
- }
- else if (G.relbase_valid) {
- char path[FILE_MAX];
- BLI_strncpy(path, G.main->name, sizeof(G.main->name));
- BLI_parent_dir(path);
- RNA_string_set(op->ptr, "filepath", path);
- }
- WM_event_add_fileselect(C, op);
- return OPERATOR_RUNNING_MODAL;
- }
-}
-
-static short wm_link_append_flag(wmOperator *op)
-{
- PropertyRNA *prop;
- short flag = 0;
-
- if (RNA_boolean_get(op->ptr, "autoselect"))
- flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer"))
- flag |= FILE_ACTIVELAY;
- if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
- flag |= FILE_RELPATH;
- if (RNA_boolean_get(op->ptr, "link"))
- flag |= FILE_LINK;
- if (RNA_boolean_get(op->ptr, "instance_groups"))
- flag |= FILE_GROUP_INSTANCE;
-
- return flag;
-}
-
-typedef struct WMLinkAppendDataItem {
- char *name;
- BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
- short idcode;
-
- ID *new_id;
- void *customdata;
-} WMLinkAppendDataItem;
-
-typedef struct WMLinkAppendData {
- LinkNodePair libraries;
- LinkNodePair items;
- int num_libraries;
- int num_items;
- short flag;
-
- /* Internal 'private' data */
- MemArena *memarena;
-} WMLinkAppendData;
-
-static WMLinkAppendData *wm_link_append_data_new(const int flag)
-{
- MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
-
- lapp_data->flag = flag;
- lapp_data->memarena = ma;
-
- return lapp_data;
-}
-
-static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
-{
- BLI_memarena_free(lapp_data->memarena);
-}
-
-/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
-
-static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
-{
- size_t len = strlen(libname) + 1;
- char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
-
- BLI_strncpy(libpath, libname, len);
- BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
- lapp_data->num_libraries++;
-}
-
-static WMLinkAppendDataItem *wm_link_append_data_item_add(
- WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata)
-{
- WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
- size_t len = strlen(idname) + 1;
-
- item->name = BLI_memarena_alloc(lapp_data->memarena, len);
- BLI_strncpy(item->name, idname, len);
- item->idcode = idcode;
- item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
-
- item->new_id = NULL;
- item->customdata = customdata;
-
- BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
- lapp_data->num_items++;
-
- return item;
-}
-
-static void wm_link_do(
- WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
-{
- Main *mainl;
- BlendHandle *bh;
- Library *lib;
-
- const int flag = lapp_data->flag;
-
- LinkNode *liblink, *itemlink;
- int lib_idx, item_idx;
-
- BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
-
- for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
- char *libname = liblink->link;
-
- bh = BLO_blendhandle_from_file(libname, reports);
-
- if (bh == NULL) {
- /* Unlikely since we just browsed it, but possible
- * Error reports will have been made by BLO_blendhandle_from_file() */
- continue;
- }
-
- /* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &bh, libname);
- lib = mainl->curlib;
- BLI_assert(lib);
- UNUSED_VARS_NDEBUG(lib);
-
- if (mainl->versionfile < 250) {
- BKE_reportf(reports, RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile, mainl->subversionfile);
- }
-
- /* For each lib file, we try to link all items belonging to that lib,
- * and tag those successful to not try to load them again with the other libs. */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *new_id;
-
- if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
- continue;
- }
-
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
- if (new_id) {
- /* If the link is sucessful, clear item's libs 'todo' flags.
- * This avoids trying to link same item with other libraries to come. */
- BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
- item->new_id = new_id;
- }
- }
-
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
- BLO_blendhandle_close(bh);
- }
-}
-
-static int wm_link_append_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
- char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
- char *group, *name;
- int totfiles = 0;
- short flag;
-
- RNA_string_get(op->ptr, "filename", relname);
- RNA_string_get(op->ptr, "directory", root);
-
- BLI_join_dirfile(path, sizeof(path), root, relname);
-
- /* test if we have a valid data */
- if (!BLO_library_path_explode(path, libname, &group, &name)) {
- BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
- return OPERATOR_CANCELLED;
- }
- else if (!group) {
- BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
- return OPERATOR_CANCELLED;
- }
- else if (BLI_path_cmp(bmain->name, libname) == 0) {
- BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
- return OPERATOR_CANCELLED;
- }
-
- /* check if something is indicated for append/link */
- prop = RNA_struct_find_property(op->ptr, "files");
- if (prop) {
- totfiles = RNA_property_collection_length(op->ptr, prop);
- if (totfiles == 0) {
- if (!name) {
- BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
- return OPERATOR_CANCELLED;
- }
- }
- }
- else if (!name) {
- BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
- return OPERATOR_CANCELLED;
- }
-
- flag = wm_link_append_flag(op);
-
- /* sanity checks for flag */
- if (scene && scene->id.lib) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2);
- flag &= ~FILE_GROUP_INSTANCE;
- scene = NULL;
- }
-
- /* from here down, no error returns */
-
- if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
- BKE_scene_base_deselect_all(scene);
- }
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* We define our working data...
- * Note that here, each item 'uses' one library, and only one. */
- lapp_data = wm_link_append_data_new(flag);
- if (totfiles != 0) {
- GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
- int lib_idx = 0;
-
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- RNA_string_get(&itemptr, "name", relname);
-
- BLI_join_dirfile(path, sizeof(path), root, relname);
-
- if (BLO_library_path_explode(path, libname, &group, &name)) {
- if (!group || !name) {
- continue;
- }
-
- if (!BLI_ghash_haskey(libraries, libname)) {
- BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
- lib_idx++;
- wm_link_append_data_library_add(lapp_data, libname);
- }
- }
- }
- RNA_END;
-
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- RNA_string_get(&itemptr, "name", relname);
-
- BLI_join_dirfile(path, sizeof(path), root, relname);
-
- if (BLO_library_path_explode(path, libname, &group, &name)) {
- WMLinkAppendDataItem *item;
- if (!group || !name) {
- printf("skipping %s\n", path);
- continue;
- }
-
- lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
-
- item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, lib_idx);
- }
- }
- RNA_END;
-
- BLI_ghash_free(libraries, MEM_freeN, NULL);
- }
- else {
- WMLinkAppendDataItem *item;
-
- wm_link_append_data_library_add(lapp_data, libname);
- item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
- }
-
- /* XXX We'd need re-entrant locking on Main for this to work... */
- /* BKE_main_lock(bmain); */
-
- wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
-
- /* BKE_main_unlock(bmain); */
-
- wm_link_append_data_free(lapp_data);
-
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* append, rather than linking */
- if ((flag & FILE_LINK) == 0) {
- bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
- BKE_library_make_local(bmain, NULL, true, set_fake);
- }
-
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
-
- /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
- BLI_strncpy(G.lib, root, FILE_MAX);
-
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
-{
- PropertyRNA *prop;
-
- /* better not save _any_ settings for this operator */
- /* properties */
- prop = RNA_def_boolean(ot->srna, "link", is_link,
- "Link", "Link the objects or datablocks rather than appending");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
- prop = RNA_def_boolean(ot->srna, "autoselect", true,
- "Select", "Select new objects");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "active_layer", true,
- "Active Layer", "Put new objects on the active layer");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
- "Instance Groups", "Create Dupli-Group instances for each group");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static void WM_OT_link(wmOperatorType *ot)
-{
- ot->name = "Link from Library";
- ot->idname = "WM_OT_link";
- ot->description = "Link from a Library .blend file";
-
- ot->invoke = wm_link_append_invoke;
- ot->exec = wm_link_append_exec;
- ot->poll = wm_link_append_poll;
-
- ot->flag |= OPTYPE_UNDO;
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- wm_link_append_properties_common(ot, true);
-}
-
-static void WM_OT_append(wmOperatorType *ot)
-{
- ot->name = "Append from Library";
- ot->idname = "WM_OT_append";
- ot->description = "Append from a Library .blend file";
-
- ot->invoke = wm_link_append_invoke;
- ot->exec = wm_link_append_exec;
- ot->poll = wm_link_append_poll;
-
- ot->flag |= OPTYPE_UNDO;
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- wm_link_append_properties_common(ot, false);
- RNA_def_boolean(ot->srna, "set_fake", false, "Fake User", "Set Fake User for appended items (except Objects and Groups)");
-}
-
-/* *************** recover last session **************** */
-
-void WM_recover_last_session(bContext *C, ReportList *reports)
-{
- char filepath[FILE_MAX];
-
- BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
- /* if reports==NULL, it's called directly without operator, we add a quick check here */
- if (reports || BLI_exists(filepath)) {
- G.fileflags |= G_FILE_RECOVER;
-
- wm_file_read_opwrap(C, filepath, reports, true);
-
- G.fileflags &= ~G_FILE_RECOVER;
-
- /* XXX bad global... fixme */
- if (G.main->name[0])
- G.file_loaded = 1; /* prevents splash to show */
- else {
- G.relbase_valid = 0;
- G.save_over = 0; /* start with save preference untitled.blend */
- }
-
- }
-}
-
-static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
-{
- WM_recover_last_session(C, op->reports);
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_recover_last_session(wmOperatorType *ot)
-{
- ot->name = "Recover Last Session";
- ot->idname = "WM_OT_recover_last_session";
- ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
- ot->invoke = WM_operator_confirm;
-
- ot->exec = wm_recover_last_session_exec;
-}
-
-/* *************** recover auto save **************** */
-
-static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
-{
- char filepath[FILE_MAX];
- bool success;
-
- RNA_string_get(op->ptr, "filepath", filepath);
-
- G.fileflags |= G_FILE_RECOVER;
-
- success = wm_file_read_opwrap(C, filepath, op->reports, true);
-
- G.fileflags &= ~G_FILE_RECOVER;
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- char filename[FILE_MAX];
-
- wm_autosave_location(filename);
- RNA_string_set(op->ptr, "filepath", filename);
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void WM_OT_recover_auto_save(wmOperatorType *ot)
-{
- ot->name = "Recover Auto Save";
- ot->idname = "WM_OT_recover_auto_save";
- ot->description = "Open an automatically saved file to recover it";
-
- ot->exec = wm_recover_auto_save_exec;
- ot->invoke = wm_recover_auto_save_invoke;
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
-}
-
-/* *************** save file as **************** */
-
-static void wm_filepath_default(char *filepath)
-{
- if (G.save_over == false) {
- BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
- }
-}
-
-static void save_set_compress(wmOperator *op)
-{
- PropertyRNA *prop;
-
- prop = RNA_struct_find_property(op->ptr, "compress");
- if (!RNA_property_is_set(op->ptr, prop)) {
- if (G.save_over) { /* keep flag for existing file */
- RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
- }
- else { /* use userdef for new file */
- RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
- }
- }
-}
-
-static void save_set_filepath(wmOperator *op)
-{
- PropertyRNA *prop;
- char name[FILE_MAX];
-
- prop = RNA_struct_find_property(op->ptr, "filepath");
- if (!RNA_property_is_set(op->ptr, prop)) {
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
- }
- else {
- BLI_strncpy(name, G.main->name, FILE_MAX);
- }
-
- wm_filepath_default(name);
- RNA_property_string_set(op->ptr, prop, name);
- }
-}
-
-static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
-
- save_set_compress(op);
- save_set_filepath(op);
-
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* function used for WM_OT_save_mainfile too */
-static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
-{
- char path[FILE_MAX];
- int fileflags;
-
- save_set_compress(op);
-
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- RNA_string_get(op->ptr, "filepath", path);
- }
- else {
- BLI_strncpy(path, G.main->name, FILE_MAX);
- wm_filepath_default(path);
- }
-
- fileflags = G.fileflags & ~G_FILE_USERPREFS;
-
- /* set compression flag */
- BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
- G_FILE_COMPRESS);
- BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
- G_FILE_RELATIVE_REMAP);
- BKE_BIT_TEST_SET(fileflags,
- (RNA_struct_property_is_set(op->ptr, "copy") &&
- RNA_boolean_get(op->ptr, "copy")),
- G_FILE_SAVE_COPY);
-
-#ifdef USE_BMESH_SAVE_AS_COMPAT
- BKE_BIT_TEST_SET(fileflags,
- (RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
- RNA_boolean_get(op->ptr, "use_mesh_compat")),
- G_FILE_MESH_COMPAT);
-#else
-# error "don't remove by accident"
-#endif
-
- if (wm_file_write(C, path, fileflags, op->reports) != 0)
- return OPERATOR_CANCELLED;
-
- WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-/* function used for WM_OT_save_mainfile too */
-static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
-{
- char filepath[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", filepath);
- if (!BLO_has_bfile_extension(filepath)) {
- /* some users would prefer BLI_replace_extension(),
- * we keep getting nitpicking bug reports about this - campbell */
- BLI_ensure_extension(filepath, FILE_MAX, ".blend");
- RNA_string_set(op->ptr, "filepath", filepath);
- return true;
- }
- return false;
-}
-
-static void WM_OT_save_as_mainfile(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- ot->name = "Save As Blender File";
- ot->idname = "WM_OT_save_as_mainfile";
- ot->description = "Save the current file in the desired location";
-
- ot->invoke = wm_save_as_mainfile_invoke;
- ot->exec = wm_save_as_mainfile_exec;
- ot->check = blend_save_check;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
- RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
- "Remap relative paths when saving in a different directory");
- prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
- "Save a copy of the actual working state but does not make saved file active");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-#ifdef USE_BMESH_SAVE_AS_COMPAT
- RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
- "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
- "be lost (no implicit triangulation)");
-#endif
-}
-
-/* *************** save file directly ******** */
-
-static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- int ret;
-
- /* cancel if no active window */
- if (CTX_wm_window(C) == NULL)
- return OPERATOR_CANCELLED;
-
- save_set_compress(op);
- save_set_filepath(op);
-
- /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
- * enable the option to remap paths to avoid confusion [#37240] */
- if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
- if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, true);
- }
- }
-
- if (G.save_over) {
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
- if (BLI_exists(path)) {
- ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
- }
- else {
- ret = wm_save_as_mainfile_exec(C, op);
- }
- }
- else {
- WM_event_add_fileselect(C, op);
- ret = OPERATOR_RUNNING_MODAL;
- }
-
- return ret;
-}
-
-static void WM_OT_save_mainfile(wmOperatorType *ot)
-{
- ot->name = "Save Blender File";
- ot->idname = "WM_OT_save_mainfile";
- ot->description = "Save the current Blender file";
-
- ot->invoke = wm_save_mainfile_invoke;
- ot->exec = wm_save_as_mainfile_exec;
- ot->check = blend_save_check;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
- RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
- "Remap relative paths when saving in a different directory");
-}
-
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
{
ot->name = "Toggle Window Fullscreen";
@@ -3872,7 +2845,6 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize)
#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
-#define WM_RADIAL_CONTROL_HEADER_LENGTH 180
#define WM_RADIAL_MAX_STR 10
typedef struct {
@@ -3898,7 +2870,7 @@ typedef struct {
static void radial_control_update_header(wmOperator *op, bContext *C)
{
RadialControl *rc = op->customdata;
- char msg[WM_RADIAL_CONTROL_HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
@@ -3906,34 +2878,33 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
if (hasNumInput(&rc->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&rc->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str);
- ED_area_headerprint(sa, msg);
+ BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
}
else {
const char *ui_name = RNA_property_ui_name(rc->prop);
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %0.4f", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
break;
case PROP_PIXEL:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
+ BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
break;
case PROP_PERCENTAGE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.1f%%", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
break;
case PROP_FACTOR:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %1.3f", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
break;
case PROP_ANGLE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
break;
default:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s", ui_name); /* XXX: No value? */
+ BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
break;
}
- ED_area_headerprint(sa, msg);
}
+ ED_area_headerprint(sa, msg);
}
}
@@ -4151,7 +3122,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
BLF_size(fontid, 1.5 * fstyle_points, 1.0f / U.dpi);
BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, 0.0f, 0.0f, 0.0f, 0.5f);
+ BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
BLF_shadow_offset(fontid, 1, -1);
/* draw value */
@@ -5323,6 +4294,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
+ WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_border");
}
@@ -5357,6 +4329,7 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
+ WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
}
/* default keymap for windows and screens, only call once per WM */
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 675958cf0a3..6bf7bcc2934 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -897,6 +897,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
break;
case GHOST_kKeyEqual:
+ case GHOST_kKeyPlus:
case GHOST_kKeyNumpadPlus:
{
if (val == 0) break;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 688be21cdd0..42f6585f152 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -457,7 +457,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
/* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
U.pixelsize = wm_window_pixelsize(win);
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
wm_window_swap_buffers(win);
@@ -834,7 +834,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
/* this can change per window */
U.pixelsize = wm_window_pixelsize(win);
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
}
}
@@ -1197,7 +1197,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
// printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
U.pixelsize = wm_window_pixelsize(win);
- BKE_userdef_state();
+ BKE_blender_userdef_refresh();
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index e99f80f53cd..c695a12f52c 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -111,7 +111,7 @@ enum {
struct wmWindow;
struct wmEvent;
-int wm_cursor_arrow_move(struct wmWindow *win, struct wmEvent *event);
+bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event);
#endif /* __WM_CURSORS_H__ */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index c32ded28126..449612bc5fd 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -167,6 +167,7 @@ enum {
QUOTEKEY = 0x00e4, /* 228 */
ACCENTGRAVEKEY = 0x00e5, /* 229 */
MINUSKEY = 0x00e6, /* 230 */
+ PLUSKEY = 0x00e7, /* 231 */
SLASHKEY = 0x00e8, /* 232 */
BACKSLASHKEY = 0x00e9, /* 233 */
EQUALKEY = 0x00ea, /* 234 */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 4b35f662a99..2eae9cdb012 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -31,15 +31,33 @@
#ifndef __WM_FILES_H__
#define __WM_FILES_H__
+struct wmOperatorType;
+
+/* wm_files.c */
void wm_history_file_read(void);
-int wm_history_file_read_exec(bContext *C, wmOperator *op);
-int wm_file_write(struct bContext *C, const char *target, int fileflags, struct ReportList *reports);
-int wm_homefile_read_exec(struct bContext *C, struct wmOperator *op);
int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath);
-int wm_homefile_write_exec(struct bContext *C, struct wmOperator *op);
-int wm_userpref_write_exec(struct bContext *C, struct wmOperator *op);
void wm_file_read_report(bContext *C);
+void WM_OT_save_homefile(struct wmOperatorType *ot);
+void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot);
+void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot);
+void WM_OT_save_userpref(struct wmOperatorType *ot);
+void WM_OT_read_history(struct wmOperatorType *ot);
+void WM_OT_read_homefile(struct wmOperatorType *ot);
+void WM_OT_read_factory_settings(struct wmOperatorType *ot);
+
+void WM_OT_open_mainfile(struct wmOperatorType *ot);
+
+void WM_OT_revert_mainfile(struct wmOperatorType *ot);
+void WM_OT_recover_last_session(struct wmOperatorType *ot);
+void WM_OT_recover_auto_save(struct wmOperatorType *ot);
+
+void WM_OT_save_as_mainfile(struct wmOperatorType *ot);
+void WM_OT_save_mainfile(struct wmOperatorType *ot);
+
+/* wm_files_link.c */
+void WM_OT_link(struct wmOperatorType *ot);
+void WM_OT_append(struct wmOperatorType *ot);
#endif /* __WM_FILES_H__ */