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:
authorBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
commitfaec4309147988fbab7b7d7ec661f5130358d169 (patch)
tree0c839f8f88fe80f4a3762980adb5efe729ce1b44 /source/blender
parentf85745b17bfe68673bf5f799e98c617d9471ddf1 (diff)
parente1dd83b399d46d81ea51f6c41725eec5c1a1db7a (diff)
Merge branch 'master' into blender2.8
Conflicts: intern/cycles/blender/blender_curves.cpp source/blender/blenkernel/intern/dynamicpaint.c source/blender/blenkernel/intern/particle.c source/blender/blenloader/intern/versioning_270.c source/blender/editors/physics/particle_edit.c source/blender/editors/transform/transform_snap_object.c source/blender/editors/util/undo.c source/blender/makesrna/intern/rna_object_force.c
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-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_version.h2
-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_dynamicpaint.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h5
-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/intern/DerivedMesh.c93
-rw-r--r--source/blender/blenkernel/intern/action.c131
-rw-r--r--source/blender/blenkernel/intern/armature.c220
-rw-r--r--source/blender/blenkernel/intern/armature_update.c14
-rw-r--r--source/blender/blenkernel/intern/blendfile.c3
-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.c21
-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.c77
-rw-r--r--source/blender/blenkernel/intern/curve.c20
-rw-r--r--source/blender/blenkernel/intern/customdata.c54
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4505
-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/gpencil.c10
-rw-r--r--source/blender/blenkernel/intern/image.c37
-rw-r--r--source/blender/blenkernel/intern/image_gen.c261
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/library.c13
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c45
-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/pbvh.c11
-rw-r--r--source/blender/blenkernel/intern/scene.c9
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c2
-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.c23
-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.h4
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h3
-rw-r--r--source/blender/blenlib/BLI_math_vector.h6
-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.c34
-rw-r--r--source/blender/blenlib/intern/math_matrix.c15
-rw-r--r--source/blender/blenlib/intern/math_vector.c42
-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.c9
-rw-r--r--source/blender/blenlib/intern/task.c442
-rw-r--r--source/blender/blenloader/intern/readfile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_270.c100
-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.h2
-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_primitive.c16
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c21
-rw-r--r--source/blender/compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cpp7
-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_nodes.cc7
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc9
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc222
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc60
-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/anim_channels_defines.c3
-rw-r--r--source/blender/editors/animation/anim_markers.c10
-rw-r--r--source/blender/editors/armature/armature_add.c40
-rw-r--r--source/blender/editors/armature/armature_edit.c5
-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.c128
-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/curve_intern.h1
-rw-r--r--source/blender/editors/curve/curve_ops.c9
-rw-r--r--source/blender/editors/curve/editcurve.c113
-rw-r--r--source/blender/editors/curve/editcurve_paint.c30
-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.c21
-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.c79
-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_utils.c18
-rw-r--r--source/blender/editors/include/BIF_glutil.h18
-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_transform.h92
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h140
-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.c46
-rw-r--r--source/blender/editors/interface/interface_icons.c78
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/interface/interface_widgets.c15
-rw-r--r--source/blender/editors/interface/resources.c18
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c31
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c8
-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_tools.c23
-rw-r--r--source/blender/editors/mesh/meshtools.c10
-rw-r--r--source/blender/editors/object/object_vgroup.c55
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c8
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/glutil.c104
-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.c13
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2
-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_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.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c10
-rw-r--r--source/blender/editors/space_graph/graph_intern.h2
-rw-r--r--source/blender/editors/space_graph/graph_ops.c6
-rw-r--r--source/blender/editors/space_graph/graph_select.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.c92
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c1
-rw-r--r--source/blender/editors/space_node/node_relationships.c6
-rw-r--r--source/blender/editors/space_node/node_templates.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c117
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c102
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c16
-rw-r--r--source/blender/editors/space_view3d/drawobject.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c81
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h7
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c53
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c237
-rw-r--r--source/blender/editors/transform/transform.h3
-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.c13
-rw-r--r--source/blender/editors/transform/transform_snap.c440
-rw-r--r--source/blender/editors/transform/transform_snap_object.c799
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/undo.c13
-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/GPU_material.h1
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c3
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c2
-rw-r--r--source/blender/gpu/intern/gpu_draw.c76
-rw-r--r--source/blender/gpu/intern/gpu_material.c21
-rw-r--r--source/blender/gpu/intern/gpu_shader.c4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl152
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl1108
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl2
-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/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/openexr/openexr_api.cpp53
-rw-r--r--source/blender/imbuf/intern/rectop.c63
-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_customdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h19
-rw-r--r--source/blender/makesdna/DNA_node_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h6
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h7
-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_armature.c78
-rw-r--r--source/blender/makesrna/intern/rna_brush.c8
-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_gpencil.c29
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c6
-rw-r--r--source/blender/makesrna/intern/rna_pose.c86
-rw-r--r--source/blender/makesrna/intern/rna_scene.c11
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_space.c11
-rw-r--r--source/blender/makesrna/intern/rna_tracking.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/nodes/shader/node_shader_tree.c160
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c2
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp2
-rw-r--r--source/blender/python/generic/py_capi_utils.c4
-rw-r--r--source/blender/python/intern/bpy_driver.c2
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c2
-rw-r--r--source/blender/python/intern/bpy_util.c2
-rw-r--r--source/blender/python/intern/gpu.c3
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c8
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp4
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c3
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c33
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c22
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c1
-rw-r--r--source/blender/windowmanager/wm_event_types.h1
291 files changed, 10998 insertions, 4908 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 7419b182c04..2b13a847e14 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -181,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;
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_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 5e7fdb91645..618b36c5851 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 277
-#define BLENDER_SUBVERSION 0
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
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 38ee690b857..ddc9fa530de 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_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 142ef1893ce..c552a618cd8 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -81,7 +81,7 @@ void dynamicPaint_resetPreview(struct DynamicPaintCanvasSettings *canvas);
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
/* image sequence baking */
-int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c7b49e00da8..727818383b1 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_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index d7dd9ed3ac5..dff79b6cc22 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -114,6 +114,11 @@ void BKE_mesh_vert_loop_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MPoly *mface, const struct MLoop *mloop,
int totvert, int totface, int totloop);
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MVert *mvert, const int totvert,
+ const struct MLoopTri *mlooptri, const int totlooptri,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index c6f8befe964..ab0b120faf3 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/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index a32fd99aa04..bcc3b60b34e 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -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)
@@ -3626,12 +3629,41 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
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) {
+ int type = gattribs->layer[b].type;
+ layer = -1;
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (gattribs->layer[b].name[0]) {
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ type = CD_MCOL;
+ }
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ type = CD_MTFACE;
+ }
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+ if (type == CD_MTFACE) {
/* uv coordinates */
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ }
a = attribs->tottface++;
@@ -3647,11 +3679,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
- else if (gattribs->layer[b].type == CD_MCOL) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ else if (type == CD_MCOL) {
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ }
a = attribs->totmcol++;
@@ -3667,13 +3701,14 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_TANGENT) {
+ else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-
- 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);
+ if (layer == -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++;
@@ -3688,9 +3723,11 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_ORCO) {
+ else if (type == CD_ORCO) {
/* original coordinates */
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ if (layer == -1) {
+ layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ }
attribs->totorco = 1;
if (layer != -1) {
@@ -3754,17 +3791,17 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
/* vertex colors */
for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
+ GLfloat col[4];
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ zero_v4(col);
}
- glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
}
/* tangent for normal mapping */
@@ -3996,7 +4033,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 5b1bb8cb2bb..df9b9683687 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;
@@ -596,7 +598,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
outPose = MEM_callocN(sizeof(bPose), "pose");
BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
-
+
+ /* Rebuild ghash here too, so that name lookups below won't be too bad...
+ * BUT this will have the penalty that the ghash will be built twice
+ * if BKE_pose_rebuild() gets called after this...
+ */
+ if (outPose->chanbase.first != outPose->chanbase.last) {
+ outPose->chanhash = NULL;
+ BKE_pose_channels_hash_make(outPose);
+ }
+
outPose->iksolver = src->iksolver;
outPose->ikdata = NULL;
outPose->ikparam = MEM_dupallocN(src->ikparam);
@@ -608,10 +619,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
id_us_plus(&pchan->custom->id);
}
- /* warning, O(n2) here, but it's a rarely used feature. */
+ /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
if (pchan->custom_tx) {
pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
}
+ if (pchan->bbone_prev) {
+ pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
+ }
+ if (pchan->bbone_next) {
+ pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
+ }
if (copy_constraints) {
BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb
@@ -726,7 +743,7 @@ void BKE_pose_channels_remove(
Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
{
- /* First erase any associated pose channel */
+ /* Erase any associated pose channel, along with any references to them */
if (ob->pose) {
bPoseChannel *pchan, *pchan_next;
bConstraint *con;
@@ -735,6 +752,7 @@ void BKE_pose_channels_remove(
pchan_next = pchan->next;
if (filter_fn(pchan->name, user_data)) {
+ /* Bone itself is being removed */
BKE_pose_channel_free(pchan);
if (ob->pose->chanhash) {
BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
@@ -742,6 +760,7 @@ void BKE_pose_channels_remove(
BLI_freelinkN(&ob->pose->chanbase, pchan);
}
else {
+ /* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -765,6 +784,20 @@ void BKE_pose_channels_remove(
cti->flush_constraint_targets(con, &targets, 0);
}
}
+
+ if (pchan->bbone_prev) {
+ if (filter_fn(pchan->bbone_prev->name, user_data))
+ pchan->bbone_prev = NULL;
+ }
+ if (pchan->bbone_next) {
+ if (filter_fn(pchan->bbone_next->name, user_data))
+ pchan->bbone_next = NULL;
+ }
+
+ if (pchan->custom_tx) {
+ if (filter_fn(pchan->custom_tx->name, user_data))
+ pchan->custom_tx = NULL;
+ }
}
}
}
@@ -824,26 +857,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);
}
@@ -869,6 +911,15 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
pchan->flag = chan->flag;
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
con = chan->constraints.first;
for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
pcon->enforce = con->enforce;
@@ -879,7 +930,7 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only).
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
*
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_verify)
*/
@@ -902,6 +953,11 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->ikstretch = pchan_from->ikstretch;
pchan->ikrotweight = pchan_from->ikrotweight;
pchan->iklinweight = pchan_from->iklinweight;
+
+ /* bbone settings (typically not animated) */
+ pchan->bboneflag = pchan_from->bboneflag;
+ pchan->bbone_next = pchan_from->bbone_next;
+ pchan->bbone_prev = pchan_from->bbone_prev;
/* constraints */
BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
@@ -1271,6 +1327,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 :) */
@@ -1330,8 +1398,13 @@ void BKE_pose_rest(bPose *pose)
unit_qt(pchan->quat);
unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->curveInX = pchan->curveInY = 0.0f;
+ pchan->curveOutX = pchan->curveOutY = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
}
}
@@ -1366,9 +1439,19 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
pchanto->rotmode = pchanfrom->rotmode;
pchanto->flag = pchanfrom->flag;
pchanto->protectflag = pchanfrom->protectflag;
+ pchanto->bboneflag = pchanfrom->bboneflag;
}
}
return true;
@@ -1415,7 +1498,13 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */
if (pose) {
- BKE_pose_channels_hash_make(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);
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 564c670fb3a..04b4733fd44 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];
@@ -473,7 +475,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2;
+ float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
@@ -494,16 +496,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 +530,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) {
@@ -536,7 +560,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
normalize_v3(h1);
- mul_v3_fl(h1, -hlength1);
+ negate_v3(h1);
if (prev->bone->segments == 1) {
/* find the previous roll to interpolate */
@@ -555,17 +579,34 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- h1[0] = 0.0f; h1[1] = hlength1; h1[2] = 0.0f;
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
if (next) {
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 */
@@ -591,14 +632,66 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = atan2f(mat3[2][0], mat3[2][2]);
- /* and only now negate handle */
- mul_v3_fl(h2, -hlength2);
}
else {
- h2[0] = 0.0f; h2[1] = -hlength2; h2[2] = 0.0f;
+ h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
roll2 = 0.0;
}
+ {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+ const float hlength1 = bone->ease1 * circle_factor;
+ const float hlength2 = bone->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
+ /* 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 +701,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);
+ }
+
}
}
@@ -667,7 +785,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 +798,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 +971,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)
@@ -897,19 +1040,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/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 4605a12f9a0..bedf262541f 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -492,6 +492,9 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
/* 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;
}
}
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 87dc08e5124..9c163990dd2 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -491,11 +491,12 @@ static void cdDM_drawFacesTex_common(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
int i;
int colType, start_element, tot_drawn;
const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
int totpoly;
int next_actualFace;
int mat_index;
@@ -525,15 +526,17 @@ static void cdDM_drawFacesTex_common(
}
}
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 9454ad62ed3..fa0960515b4 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -57,6 +57,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 );
@@ -346,6 +347,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)
@@ -569,6 +574,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)||
@@ -609,6 +615,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;
@@ -646,16 +655,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;
- }
}
}
}
@@ -663,6 +670,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)
{
@@ -720,11 +744,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 */
@@ -736,6 +760,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 );
@@ -1079,6 +1105,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);
@@ -1118,7 +1191,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);
@@ -1162,19 +1235,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++;
@@ -1186,11 +1259,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
@@ -1212,10 +1286,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;
@@ -1259,7 +1330,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 1b9ac499e1f..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... */
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 b0d0dc08126..de79a30bd60 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -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/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 73d64c23840..7842d561557 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -65,6 +66,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -78,13 +80,11 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
+#include "atomic_ops.h"
/* 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 */
@@ -122,7 +122,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))) :
@@ -137,19 +137,20 @@ typedef struct Bounds2D {
} Bounds2D;
typedef struct Bounds3D {
- int valid;
float min[3], max[3];
+ bool valid;
} 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) */
+ int *temp_t_index;
} VolumeGrid;
typedef struct Vec3f {
@@ -164,21 +165,21 @@ 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;
+ float dim[3];
/* 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 */
@@ -187,11 +188,10 @@ 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. */
-
} PaintBakeData;
/* UV Image sequence format point */
@@ -200,8 +200,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 {
@@ -213,8 +212,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 */
@@ -238,11 +236,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 */
@@ -252,32 +249,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 */
@@ -291,8 +272,9 @@ void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
surface->flags |= MOD_DPAINT_PREVIEW;
done = true;
}
- else
+ else {
surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
}
@@ -324,8 +306,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;
@@ -333,15 +316,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;
@@ -351,20 +335,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;
}
@@ -419,9 +408,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 &&
@@ -433,8 +420,10 @@ static int surface_totalSamples(DynamicPaintSurface *surface)
return surface->data->total_points;
}
-static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
+static void blendColors(
+ const float t_color[3], const float t_alpha, const float s_color[3], const 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;
@@ -507,15 +496,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)
@@ -523,6 +508,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;
@@ -539,56 +528,58 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
return flags;
}
-static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
+static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
{
return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(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 UNUSED_FUNCTION(boundIntersectPoint)(Bounds3D *b, float point[3], float radius)
+static bool UNUSED_FUNCTION(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;
- }
- 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];
- }
+ b->valid = true;
+ return;
}
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
@@ -611,65 +602,123 @@ static void freeGrid(PaintSurfaceData *data)
bData->grid = NULL;
}
+static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+}
+
+static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
+}
+
+static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = userdata_chunk;
+
+ int co[3];
+
+ for (int j = 3; j--;) {
+ co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
+ bData->dim[j] * grid->dim[j]);
+ CLAMP(co[j], 0, grid->dim[j] - 1);
+ }
+
+ temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
+ s_num[temp_t_index[i]]++;
+}
+
+static void grid_cell_points_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ int *s_num = userdata_chunk;
+
+ /* calculate grid indexes */
+ for (int i = 0; i < grid_cells; i++) {
+ grid->s_num[i] += s_num[i];
+ }
+}
+
+static void grid_cell_bounds_cb(void *userdata, const int x)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ float *dim = bData->dim;
+ int *grid_dim = grid->dim;
+
+ for (int y = 0; y < grid_dim[1]; y++) {
+ for (int z = 0; z < grid_dim[2]; z++) {
+ const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
+ /* set bounds */
+ for (int j = 3; j--;) {
+ const int s = (j == 0) ? x : ((j == 1) ? y : z);
+ grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
+ grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
+ }
+ grid->bounds[b_index].valid = true;
+ }
+ }
+}
+
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Bounds3D *grid_bounds;
VolumeGrid *grid;
int grid_cells, axis = 3;
int *temp_t_index = NULL;
int *temp_s_num = NULL;
-#ifdef _OPENMP
- int num_of_threads = omp_get_max_threads();
-#else
- int num_of_threads = 1;
-#endif
-
if (bData->grid)
freeGrid(sData);
- /* allocate separate bounds for each thread */
- grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
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];
float min_dim;
/* calculate canvas dimensions */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
-#ifdef _OPENMP
- int id = omp_get_thread_num();
- boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
-#else
- boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
-#endif
- }
-
- /* get final dimensions */
- for (i = 0; i < num_of_threads; i++) {
- boundInsert(&grid->grid_bounds, grid_bounds[i].min);
- boundInsert(&grid->grid_bounds, grid_bounds[i].max);
- }
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds),
+ grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false);
/* get dimensions */
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
copy_v3_v3(td, dim);
+ copy_v3_v3(bData->dim, dim);
min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
/* 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;
@@ -691,10 +740,11 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* allocate memory for grids */
grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
- grid->s_num = MEM_callocN(sizeof(int) * grid_cells * num_of_threads, "Surface Grid Points");
+
+ grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
- temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
+ grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
/* in case of an allocation failure abort here */
if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
@@ -702,33 +752,12 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
if (!error) {
/* calculate number of points withing each cell */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int co[3], j;
- for (j = 0; j < 3; j++) {
- co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) / dim[j] * grid->dim[j]);
- CLAMP(co[j], 0, grid->dim[j] - 1);
- }
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells,
+ grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false);
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
-#ifdef _OPENMP
- grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
-#else
- grid->s_num[temp_t_index[i]]++;
-#endif
- }
-
- /* for first cell only calc s_num */
- for (i = 1; i < num_of_threads; i++) {
- grid->s_num[0] += grid->s_num[i * grid_cells];
- }
-
- /* calculate grid indexes */
+ /* calculate grid indexes (not needed for first cell, which is zero). */
for (i = 1; i < grid_cells; i++) {
- int id;
- for (id = 1; id < num_of_threads; id++) {
- grid->s_num[i] += grid->s_num[i + id * grid_cells];
- }
grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
}
@@ -741,41 +770,20 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
/* calculate cell bounds */
- {
- int x;
-#pragma omp parallel for schedule(static)
- for (x = 0; x < grid->dim[0]; x++) {
- int y;
- for (y = 0; y < grid->dim[1]; y++) {
- int z;
- for (z = 0; z < grid->dim[2]; z++) {
- int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
- /* set bounds */
- for (j = 0; j < 3; j++) {
- int s = (j == 0) ? x : ((j == 1) ? y : z);
- grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * s;
- grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * (s + 1);
- }
- grid->bounds[b_index].valid = 1;
- }
- }
- }
- }
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000);
}
- 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);
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
+ grid->temp_t_index = NULL;
if (error || !grid->s_num) {
setError(surface->canvas, N_("Not enough free memory"));
freeGrid(sData);
}
}
-
- if (grid_bounds) MEM_freeN(grid_bounds);
}
/***************************** Freeing data ******************************/
@@ -790,10 +798,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;
@@ -803,10 +809,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;
}
@@ -816,15 +826,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;
@@ -834,11 +853,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))
- {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE)) {
free_bakeData(surface->data);
}
}
@@ -846,7 +865,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) {
@@ -859,7 +880,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);
@@ -1022,7 +1044,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
-
+
brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
@@ -1210,31 +1232,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;
@@ -1242,20 +1257,24 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int *temp_data;
int neigh_points = 0;
- if (!surface_usesAdjData(surface) && !force_init) return;
+ if (!force_init && !surface_usesAdjData(surface))
+ 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");
@@ -1266,7 +1285,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;
}
@@ -1294,8 +1314,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]++;
}
}
@@ -1303,13 +1322,11 @@ 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;
}
- /* reset temp data */
+ /* reset temp data */
temp_data[i] = 0;
}
@@ -1343,6 +1360,117 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
MEM_freeN(temp_data);
}
+typedef struct DynamicPaintSetInitColorData {
+ const DynamicPaintSurface *surface;
+
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
+
+ const bool scene_color_manage;
+} DynamicPaintSetInitColorData;
+
+static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ struct ImagePool *pool = data->pool;
+ Tex *tex = data->surface->init_texture;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[3] = {0.0f};
+
+ for (int j = 3; j--;) {
+ TexResult texres = {0};
+ const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
+
+ /* remap to [-1.0, 1.0] */
+ uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
+ uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
+
+ if (texres.tin > pPoint[vert].color[3]) {
+ copy_v3_v3(pPoint[vert].color, &texres.tr);
+ pPoint[vert].color[3] = texres.tin;
+ }
+ }
+}
+
+static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ Tex *tex = data->surface->init_texture;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
+
+ TexResult texres = {0};
+
+ /* collect all uvs */
+ for (int j = 3; j--;) {
+ copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
+ }
+
+ /* interpolate final uv pos */
+ interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
+ /* remap to [-1.0, 1.0] */
+ uv_final[0] = uv_final[0] * 2.0f - 1.0f;
+ uv_final[1] = uv_final[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
+
+ /* apply color */
+ copy_v3_v3(pPoint[i].color, &texres.tr);
+ pPoint[i].color[3] = texres.tin;
+}
+
+static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopCol *mloopcol = data->mloopcol;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const int tri_idx = f_data->uv_p[i].tri_index;
+ float colors[3][4];
+ float final_color[4];
+
+ /* collect color values */
+ for (int j = 3; j--;) {
+ rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
+ }
+
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+
+ copy_v4_v4(pPoint[i].color, final_color);
+}
+
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1356,10 +1484,10 @@ 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++) {
copy_v4_v4(pPoint[i].color, surface->init_color);
}
@@ -1375,69 +1503,36 @@ 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 */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
struct ImagePool *pool = BKE_image_pool_new();
-#pragma omp parallel for schedule(static) shared(pool)
- for (i = 0; i < tottri; i++) {
- float uv[3] = {0.0f};
- int j;
- for (j = 0; j < 3; j++) {
- TexResult texres = {0};
- unsigned int vert = mloop[mlooptri[i].tri[j]].v;
-
- /* remap to -1.0 to 1.0 */
- uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
- uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
-
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
- int j;
- TexResult texres = {0};
-
- /* collect all uvs */
- for (j = 0; j < 3; j++) {
- copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
- }
-
- /* interpolate final uv pos */
- interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6],
- f_data->barycentricWeights[i * samples].v);
- /* remap to -1.0 to 1.0 */
- uv_final[0] = uv_final[0] * 2.0f - 1.0f;
- uv_final[1] = uv_final[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
-
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb,
+ sData->total_points > 1000);
}
}
/* vertex color layer */
@@ -1448,37 +1543,25 @@ 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++) {
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- 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;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int tri_ind = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
- int j;
-
- /* collect color values */
- for (j = 0; j < 3; j++) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&col[mlooptri[tri_ind].tri[j]].r);
- }
-
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
-
- copy_v4_v4(pPoint[i].color, final_color);
- }
+ if (!col)
+ return;
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopcol = col,
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb,
+ sData->total_points > 1000);
}
}
}
@@ -1513,20 +1596,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)
@@ -1547,39 +1634,153 @@ static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurfac
/***************************** Modifier processing ******************************/
+typedef struct DynamicPaintModifierApplyData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
+
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
+} DynamicPaintModifierApplyData;
+
+static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ MVert *mvert = data->mvert;
+
+ float normal[3];
+ const float *value = (float *)surface->data->type_data;
+ const float val = value[i] * surface->disp_factor;
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+
+ /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
+ madd_v3_v3fl(mvert[i].co, normal, -val);
+}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
{
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) {
MVert *mvert = result->getVertArray(result);
- int i;
- const float *value = (float *)sData->type_data;
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3], val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
- normalize_v3(normal);
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb,
+ sData->total_points > 10000);
+ }
+}
+
+static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ /* blend dry and wet layer */
+ blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
+}
+
+static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
- mvert[i].co[0] -= normal[0] * val;
- mvert[i].co[1] -= normal[1] * val;
- mvert[i].co[2] -= normal[2] * val;
+ const DynamicPaintSurface *surface = data->surface;
+ PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ MLoopCol *mloopcol = data->mloopcol;
+ MLoopCol *mloopcol_wet = data->mloopcol_wet;
+ MLoopCol *mloopcol_preview = data->mloopcol_preview;
+
+ const Material *material = mloopcol_preview ?
+ give_current_material(ob, mpoly[p_index].mat_nr + 1) : NULL;
+
+ for (int j = 0; j < mpoly[p_index].totloop; j++) {
+ const int l_index = mpoly[p_index].loopstart + j;
+ const int v_index = mloop[l_index].v;
+
+ /* save layer data to output layer */
+ /* apply color */
+ if (mloopcol) {
+ rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
+ }
+ /* apply wetness */
+ if (mloopcol_wet) {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_wet[l_index].r = c;
+ mloopcol_wet[l_index].g = c;
+ mloopcol_wet[l_index].b = c;
+ mloopcol_wet[l_index].a = 255;
+ }
+
+ /* viewport preview */
+ if (mloopcol_preview) {
+ if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
+ float c[3];
+
+ /* Apply material color as base vertex color for preview */
+ mloopcol_preview[l_index].a = 255;
+ if (material) {
+ c[0] = material->r;
+ c[1] = material->g;
+ c[2] = material->b;
+ }
+ else { /* default gray */
+ c[0] = 0.65f;
+ c[1] = 0.65f;
+ c[2] = 0.65f;
+ }
+ /* mix surface color */
+ interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
+
+ rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
+ }
+ else {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_preview[l_index].r = c;
+ mloopcol_preview[l_index].g = c;
+ mloopcol_preview[l_index].b = c;
+ mloopcol_preview[l_index].a = 255;
+ }
}
}
}
+static void dynamic_paint_apply_surface_wave_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
+ MVert *mvert = data->mvert;
+ float normal[3];
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+ madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+}
+
/*
* 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);
@@ -1593,129 +1794,65 @@ 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) {
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
- int i;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- MLoopCol *col = NULL;
MLoop *mloop = CDDM_get_loops(result);
- int totloop = result->numLoopData;
+ const int totloop = result->numLoopData;
+ MPoly *mpoly = CDDM_get_polys(result);
+ const int totpoly = result->numPolyData;
/* paint is stored on dry and wet layers, so mix final color first */
- float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
-
-#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]);
- }
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- MPoly *mp = CDDM_get_polys(result);
- int totpoly = result->numPolyData;
-
-#if 0
- /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
- * (after a SubSurf mod, eg)... */
- if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
- int numFaces = result->getNumTessFaces(result);
- CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
- }
-#endif
-
- /* 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) {
-#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++) {
- int l_index = mp[i].loopstart + j;
- int v_index = mloop[l_index].v;
-
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
- v_index *= 4;
-
- /* Apply material color as base vertex color for preview */
- col[l_index].a = 255;
- if (material) {
- c[0] = material->r;
- c[1] = material->g;
- c[2] = material->b;
- }
- else { /* default gray */
- c[0] = 0.65f;
- c[1] = 0.65f;
- c[2] = 0.65f;
- }
- /* mix surface color */
- interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index + 3]);
-
- 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);
- col[l_index].a = 255;
- }
- }
- }
- }
- }
+ float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
-
- /* save layer data to output layer */
+ DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ sData->total_points > 1000);
/* paint layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = 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);
- /* 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? */
- }
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
-
- MEM_freeN(fcolor);
/* wet layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = 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);
- /* 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);
- col[i].a = 255;
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
+
+ /* Save preview results to weight layer to be able to share same drawing methods */
+ MLoopCol *mloopcol_preview = NULL;
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
+ data.ob = ob;
+ data.mloop = mloop;
+ data.mpoly = mpoly;
+ data.mloopcol = mloopcol;
+ data.mloopcol_wet = mloopcol_wet;
+ data.mloopcol_preview = mloopcol_preview;
+
+ BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb,
+ totpoly > 1000);
+
+ MEM_freeN(fcolor);
+
/* Mark tessellated CD layers as dirty. */
result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@@ -1734,9 +1871,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++) {
@@ -1745,7 +1883,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);
@@ -1760,15 +1897,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
MVert *mvert = result->getVertArray(result);
- int i;
- PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
- }
+
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb,
+ sData->total_points > 1000);
update_normals = true;
}
@@ -1787,7 +1919,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);
}
@@ -1816,7 +1949,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) {
@@ -1827,17 +1961,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)
+ {
surface->current_frame = current_frame;
/* if we're on surface range do recalculate */
@@ -1862,263 +1999,462 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
+ if (pmd->canvas) {
+ DerivedMesh *ret;
+
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+
+ return ret;
+ }
+ else {
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ }
}
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
- * Tries to find the neighboring pixel in given (uv space) direction.
- * Result is used by effect system to move paint on the surface.
+ * Create a surface for uv image sequence format
+ */
+#define JITTER_SAMPLES { \
+ 0.0f, 0.0f, \
+ -0.2f, -0.4f, \
+ 0.2f, 0.4f, \
+ 0.4f, -0.2f, \
+ -0.4f, 0.3f, \
+}
+
+typedef struct DynamicPaintCreateUVSurfaceData {
+ const DynamicPaintSurface *surface;
+
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
+
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
+
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
+} DynamicPaintCreateUVSurfaceData;
+
+static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+ const int tottri = data->tottri;
+
+ const Bounds2D *faceBB = data->faceBB;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+ float point[5][2];
+
+ /* Init per pixel settings */
+ tPoint->tri_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
+
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)tx + 0.5f) / w;
+ point[0][1] = ((float)ty + 0.5f) / h;
+
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)tx) / w;
+ point[1][1] = ((float)ty) / h;
+
+ point[2][0] = ((float)tx + 1) / w;
+ point[2][1] = ((float)ty) / h;
+
+ point[3][0] = ((float)tx) / w;
+ point[3][1] = ((float)ty + 1) / h;
+
+ point[4][0] = ((float)tx + 1) / w;
+ point[4][1] = ((float)ty + 1) / h;
+
+
+ /* Loop through samples, starting from middle point */
+ for (int sample = 0; sample < 5; sample++) {
+ /* Loop through every face in the mesh */
+ /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
+ for (int i = 0; i < tottri; i++) {
+ /* Check uv bb */
+ 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;
+ }
+
+ 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;
+
+ /* 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 (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(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->tri_index = i;
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+
+ uint32_t *active_points = data->active_points;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+
+ /* If point isn't on canvas mesh */
+ if (tPoint->tri_index == -1) {
+ float point[2];
+
+ /* get loop area */
+ const int u_min = (tx > 0) ? -1 : 0;
+ const int u_max = (tx < (w - 1)) ? 1 : 0;
+ const int v_min = (ty > 0) ? -1 : 0;
+ const int v_max = (ty < (h - 1)) ? 1 : 0;
+
+ point[0] = ((float)tx + 0.5f) / w;
+ point[1] = ((float)ty + 0.5f) / h;
+
+ /* search through defined area for neighbor */
+ for (int u = u_min; u <= u_max; u++) {
+ for (int v = v_min; v <= v_max; v++) {
+ /* if not this pixel itself */
+ if (u != 0 || v != 0) {
+ const int ind = (tx + u) + w * (ty + v);
+
+ /* if neighbor has index */
+ if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
+ 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;
+
+ /* tri index */
+ /* There is a low possibility of actually having a neighbor point which tri is
+ * already set from another neighbor in a separate thread here.
+ * Cheking for both tri_index and neighbour_pixel above reduces that probability
+ * but it remains possible.
+ * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
+ * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
+ */
+ tPoint->neighbour_pixel = ind - 1;
+ atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ tPoint->tri_index = i;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ /* Add b-weights per anti-aliasing sample */
+ 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(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ u = u_max + 1; /* make sure we exit outer loop as well */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_uint32(active_points, 1);
+ }
+}
+
+#undef JITTER_SAMPLES
+
+/* Tries to find the neighboring pixel in given (uv space) direction.
+ * Result is used by effect system to move paint on the surface.
*
- * px, py : origin pixel x and y
- * n_index : lookup direction index (use neighX, neighY to get final index)
+ * px, py : origin pixel x and y
+ * n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
- const char *uvname, int w, int h, int px, int py, int n_index)
+static int dynamic_paint_find_neighbour_pixel(
+ const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_looptri_map,
+ const int w, const int h, const int px, const int py, const int n_index)
{
/* Note: Current method only uses polygon edges to detect neighboring pixels.
- * -> It doesn't always lead to the optimum pixel but is accurate enough
- * and faster/simpler than including possible face tip point links)
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
*/
- int x, y;
- PaintUVPoint *tPoint = NULL;
- PaintUVPoint *cPoint = NULL;
-
/* shift position by given n_index */
- x = px + neighX[n_index];
- y = py + neighY[n_index];
+ const int x = px + neighX[n_index];
+ const int 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 */
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
+ const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
- /*
- * Check if shifted point is on same face -> it's a correct neighbor
- * (and if it isn't marked as an "edge pixel")
- */
+ /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
return (x + w * y);
- /*
- * Even if shifted point is on another face
- * -> use this point.
+ /* Even if shifted point is on another face
+ * -> use this point.
*
- * !! Replace with "is uv faces linked" check !!
- * This should work fine as long as uv island
- * margin is > 1 pixel.
+ * !! Replace with "is uv faces linked" check !!
+ * This should work fine as long as uv island margin is > 1 pixel.
*/
if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
return (x + w * y);
}
- /*
- * If we get here, the actual neighboring pixel
- * is located on a non-linked uv face, and we have to find
- * it's "real" position.
+ /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
+ * and we have to find its "real" position.
*
- * Simple neighboring face finding algorithm:
- * - find closest uv edge to shifted pixel and get
- * the another face that shares that edge
- * - find corresponding position of that new face edge
- * in uv space
+ * Simple neighboring face finding algorithm:
+ * - find closest uv edge to shifted pixel and get the another face that shares that edge
+ * - find corresponding position of that new face edge in uv space
*
- * TODO: Implement something more accurate / optimized?
+ * TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const MLoopUV *mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
/* Get closest edge to that subpixel on UV map */
- {
- float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int i, edge1_index, edge2_index,
- 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;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /*
- * Find closest edge to that pixel
- */
-
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ float pixel[2];
+ /* distances only used for comparison */
+ float dist_squared, t_dist_squared;
+ int 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;
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+ const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
- for (i = 0; i < tottri; i++) {
- /*
- * 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;
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- target_tri = i;
+ /*
+ * Find closest edge to that pixel
+ */
- /*
- * 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;
+ /* Dist to first edge */
+ e1_index = cPoint->v1;
+ e2_index = cPoint->v2;
+ edge1_index = 0;
+ edge2_index = 1;
+ dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
+
+ /* Dist to second edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v2;
+ e2_index = cPoint->v3;
+ edge1_index = 1;
+ edge2_index = 2;
+ dist_squared = t_dist_squared;
+ }
- 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;
+ /* Dist to third edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v3;
+ e2_index = cPoint->v1;
+ edge1_index = 2;
+ edge2_index = 0;
+ dist_squared = t_dist_squared;
+ }
- break;
- }
- }
+ /*
+ * Now find another face that is linked to that edge
+ */
+ target_tri = -1;
- /* If none found pixel is on mesh edge */
- if (target_tri == -1) return ON_MESH_EDGE;
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
+ const int lt_index = vert_to_looptri_map[e1_index].indices[i];
+ const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
+ const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
+ const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ BLI_assert(ELEM(e1_index, v0, v1, v2));
- //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+ if (ELEM(e2_index, v0, v1, v2)) {
+ if (lt_index == cPoint->tri_index)
+ continue;
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
- {
- return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
- }
+ target_tri = lt_index;
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- lambda = closest_to_line_v2(
- 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;
-
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
-
- mul_v2_fl(dir_vec, lambda);
-
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- 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]);
-
- /* 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;
-
- 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 found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
- return NOT_FOUND;
+ /* 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 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 none found pixel is on mesh edge */
+ if (target_tri == -1)
+ return ON_MESH_EDGE;
- return final_index;
+ /*
+ * If target face is connected in UV space as well, just use original index
+ */
+ s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
+ s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
+ t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
+ t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+
+ //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+
+ if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
+ (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
+ ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
+ {
+ return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
}
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ lambda = closest_to_line_v2(
+ closest_point, pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ sub_v2_v2v2(
+ dir_vec,
+ mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
+ mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+
+ mul_v2_fl(dir_vec, lambda);
+
+ copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ add_v2_v2(pixel, dir_vec);
+ pixel[0] = (pixel[0] * (float)w) - 0.5f;
+ pixel[1] = (pixel[1] * (float)h) - 0.5f;
+
+ 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 || 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 found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ 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;
+
+ return final_index;
}
}
-/*
- * Create a surface for uv image sequence format
- */
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
+int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
{
/* Antialias jitter point relative coords */
- const float jitter5sample[10] = {
- 0.0f, 0.0f,
- -0.2f, -0.4f,
- 0.2f, 0.4f,
- 0.4f, -0.2f,
- -0.4f, 0.3f,
- };
- int ty;
- int w, h;
- int tottri;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- int active_points = 0;
- int error = 0;
+ uint32_t active_points = 0;
+ bool error = false;
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
@@ -2132,7 +2468,9 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
Bounds2D *faceBB = NULL;
int *final_index;
- int aa_samples;
+
+ *progress = 0.0f;
+ *do_update = true;
if (!dm)
return setError(canvas, N_("Canvas mesh not updated"));
@@ -2141,7 +2479,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
mloop = dm->getLoopArray(dm);
mlooptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
+ const int tottri = dm->getNumLoopTri(dm);
/* get uv map */
if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
@@ -2155,7 +2493,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (surface->image_resolution < 16 || surface->image_resolution > 8192)
return setError(canvas, N_("Invalid resolution"));
- w = h = surface->image_resolution;
+ const int w = surface->image_resolution;
+ const int h = w;
/*
* Start generating the surface
@@ -2163,156 +2502,60 @@ 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;
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
+ if (!tempPoints)
+ error = true;
- final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
- if (!final_index) error = 1;
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
+ if (!final_index)
+ error = true;
- tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
- if (!tempWeights) error = 1;
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
+ if (!tempWeights)
+ error = true;
/*
* Generate a temporary bounding box array for UV faces to optimize
* the pixel-inside-a-face search.
*/
if (!error) {
- faceBB = (struct Bounds2D *) MEM_mallocN(tottri * sizeof(struct Bounds2D), "MPCanvasFaceBB");
- if (!faceBB) error = 1;
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
+ if (!faceBB)
+ error = true;
}
- if (!error)
- for (ty = 0; ty < tottri; ty++) {
- int i;
+ *progress = 0.01f;
+ *do_update = true;
- copy_v2_v2(faceBB[ty].min, mloopuv[mlooptri[ty].tri[0]].uv);
- copy_v2_v2(faceBB[ty].max, mloopuv[mlooptri[ty].tri[0]].uv);
+ if (!error) {
+ for (int i = 0; i < tottri; i++) {
+ copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
+ copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].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]);
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
}
}
- /*
- * Loop through every pixel and check
- * if pixel is uv-mapped on a canvas face.
- */
- if (!error) {
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- 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;
-
- /* Init per pixel settings */
- tPoint->tri_index = -1;
- tPoint->neighbour_pixel = -1;
- tPoint->pixel_index = index;
-
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)tx + 0.5f) / w;
- point[0][1] = ((float)ty + 0.5f) / h;
-
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)tx) / w;
- point[1][1] = ((float)ty) / h;
-
- point[2][0] = ((float)tx + 1) / w;
- point[2][1] = ((float)ty) / h;
-
- point[3][0] = ((float)tx) / w;
- point[3][1] = ((float)ty + 1) / h;
-
- point[4][0] = ((float)tx + 1) / w;
- point[4][1] = ((float)ty + 1) / h;
-
-
- /* 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) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int j;
-
- /* 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);
-
- /* Add b-weights per anti-aliasing sample */
- for (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);
- }
-
- /* Set surface point face values */
- tPoint->tri_index = i;
+ *progress = 0.02f;
+ *do_update = true;
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
+ DynamicPaintCreateUVSurfaceData data = {
+ .surface = surface, .tempPoints = tempPoints, .tempWeights = tempWeights,
+ .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
+ .faceBB = faceBB,
+ };
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000);
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- } /* sample loop */
- }
- }
+ *progress = 0.04f;
+ *do_update = true;
/*
* Now loop through every pixel that was left without index
@@ -2320,87 +2563,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* If so use that polygon as pixel surface.
* (To avoid seams on uv island edges)
*/
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- /* If point isn't't on canvas mesh */
- if (tPoint->tri_index == -1) {
- int u_min, u_max, v_min, v_max;
- int u, v, ind;
- float point[2];
-
- /* get loop area */
- u_min = (tx > 0) ? -1 : 0;
- u_max = (tx < (w - 1)) ? 1 : 0;
- v_min = (ty > 0) ? -1 : 0;
- v_max = (ty < (h - 1)) ? 1 : 0;
-
- point[0] = ((float)tx + 0.5f) / w;
- point[1] = ((float)ty + 0.5f) / h;
-
- /* search through defined area for neighbor */
- for (u = u_min; u <= u_max; u++)
- for (v = v_min; v <= v_max; v++) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- ind = (tx + u) + w * (ty + v);
-
- /* 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;
-
- /* 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++) {
-
- 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);
- }
-
- /* Set values */
- tPoint->neighbour_pixel = ind; /* tri index */
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
- }
- }
- }
- }
- }
+ data.active_points = &active_points;
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64);
- /*
- * When base loop is over convert found neighbor indexes to real ones
- * Also count the final number of active surface points
- */
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- if (tPoint->tri_index == -1 && tPoint->neighbour_pixel != -1)
- tPoint->tri_index = tempPoints[tPoint->neighbour_pixel].tri_index;
- if (tPoint->tri_index != -1)
- active_points++;
- }
- }
+ *progress = 0.06f;
+ *do_update = true;
/* Generate surface adjacency data. */
{
@@ -2416,25 +2583,31 @@ 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;
- unsigned int n_pos = 0;
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
+ int n_pos = 0;
+
+ MeshElemMap *vert_to_looptri_map;
+ int *vert_to_looptri_map_mem;
+
+ BKE_mesh_vert_looptri_map_create(
+ &vert_to_looptri_map, &vert_to_looptri_map_mem,
+ dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
for (int i = 0; i < 8; i++) {
-
- /* Try to find a neighboring pixel in defined direction
- * If not found, -1 is returned */
- int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i);
+ /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
+ const int n_target = dynamic_paint_find_neighbour_pixel(
+ &data, vert_to_looptri_map, w, h, tx, ty, i);
if (n_target >= 0) {
ed->n_target[n_pos] = final_index[n_target];
@@ -2448,43 +2621,50 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
}
}
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
}
}
+ *progress = 0.08f;
+ *do_update = true;
+
/* Create final surface data without inactive points */
- {
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
- if (f_data) {
- 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");
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
+ f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights),
+ "PaintUVPoint");
- if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
- }
- else {
+ if (!f_data->uv_p || !f_data->barycentricWeights)
error = 1;
- }
+ }
+ else {
+ error = 1;
+ }
- sData->total_points = active_points;
-
- /* 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);
- MEM_freeN(f_data);
- }
+ /* 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);
+ MEM_freeN(f_data);
}
- else {
- int index, cursor = 0;
- sData->total_points = active_points;
- sData->format_data = f_data;
-
- 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);
- cursor++;
- }
+ sData->total_points = 0;
+ }
+ else {
+ sData->total_points = (int)active_points;
+ sData->format_data = f_data;
+
+ for (int index = 0, cursor = 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(*tempWeights) * aa_samples);
+ cursor++;
}
}
}
@@ -2492,10 +2672,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) {
@@ -2505,38 +2689,126 @@ 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;
/* 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[0] = 1.0f;
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ }
}
-
#endif
+
dynamicPaint_setInitialColor(scene, surface);
}
+ *progress = 0.09f;
+ *do_update = true;
+
return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
+typedef struct DynamicPaintOutputSurfaceImageData {
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
+} DynamicPaintOutputSurfaceImageData;
+
+static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ /* blend wet and dry layers */
+ blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
+
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
+ }
+}
+
+static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ float depth = ((float *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth / 2.0f);
+ }
+
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
+ float depth = wPoint->height;
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ depth = (0.5f + depth / 2.0f);
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
{
- int index;
ImBuf *ibuf = NULL;
PaintSurfaceData *sData = surface->data;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
/* OpenEXR or PNG */
int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
char output_file[FILE_MAX];
@@ -2547,7 +2819,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);
@@ -2563,82 +2836,66 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
return;
}
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
-
- /* Set values of preferred type */
- if (output_layer == 1) {
- /* wetmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- 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;
- ibuf->rect_float[pos + 3] = 1.0f;
- }
- }
- else if (output_layer == 0) {
- /* Paintmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
-
- /* blend wet and dry layers */
- blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
-
- /* 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];
- }
+ DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf};
+ switch(surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* displace */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float depth = ((float *)sData->type_data)[index];
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
-
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- 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;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* waves */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- float depth = wPoint->height;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
- 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;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- }
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
/* Set output format, png in case exr isn't supported */
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
-
#ifdef WITH_OPENEXR
if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
ibuf->ftype = IMB_FTYPE_OPENEXR;
ibuf->foptions.flag |= OPENEXR_COMPRESS;
}
+ else
#endif
+ {
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15;
+ }
/* Save image */
IMB_saveiff(ibuf, output_file, IB_rectfloat);
@@ -2704,7 +2961,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
* Get material diffuse color and alpha (including linked textures) in given coordinates
*/
static void dynamicPaint_doMaterialTex(
- BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
+ const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
const float volume_co[3], const float surface_co[3],
int triIndex, DerivedMesh *orcoDm)
{
@@ -2717,9 +2974,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;
@@ -2732,7 +2991,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.
@@ -2758,10 +3017,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.
@@ -2804,15 +3062,15 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* operations when using substeps
*/
static void dynamicPaint_mixPaintColors(
- DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+ const DynamicPaintSurface *surface, const int index, const int paintFlags,
+ const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
/* Add paint */
if (!(paintFlags & MOD_DPAINT_ERASE)) {
float mix[4];
- float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale));
+ float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
/* mix brush color with wet layer color */
blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
@@ -2821,11 +3079,11 @@ static void dynamicPaint_mixPaintColors(
/* mix wetness and alpha depending on selected alpha mode */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
/* update values to the brush level unless theyre higher already */
- CLAMP_MIN(pPoint->e_color[3], *paintAlpha);
- CLAMP_MIN(pPoint->wetness, *paintWetness);
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
}
else {
- float wetness = (*paintWetness);
+ float wetness = paintWetness;
CLAMP(wetness, 0.0f, 1.0f);
pPoint->e_color[3] = mix[3];
pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
@@ -2839,7 +3097,7 @@ static void dynamicPaint_mixPaintColors(
else {
float a_ratio, a_highest;
float wetness;
- float invFact = 1.0f - (*paintAlpha);
+ float invFact = 1.0f - paintAlpha;
/*
* Make highest alpha to match erased value
@@ -2855,47 +3113,57 @@ static void dynamicPaint_mixPaintColors(
}
}
else {
- pPoint->e_color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->e_color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->color[3], 0.0f);
}
- wetness = (1.0f - (*paintWetness)) * pPoint->e_color[3];
+ wetness = (1.0f - paintWetness) * pPoint->e_color[3];
CLAMP_MAX(pPoint->wetness, wetness);
}
}
/* applies given brush intersection value for wave surface */
-static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(
+ PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
{
- float isect_change = isect_height - wPoint->brush_isect;
- int hit = 0;
+ const float isect_change = isect_height - wPoint->brush_isect;
+ const float wave_factor = brush->wave_factor;
+ bool hit = false;
+
/* intersection marked regardless of brush type or hit */
wPoint->brush_isect = isect_height;
wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
- isect_height *= brush->wave_factor;
+ isect_height *= wave_factor;
/* determine hit depending on wave_factor */
- if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
- hit = 1;
- else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
- hit = 1;
+ if (wave_factor > 0.0f && wPoint->height > isect_height)
+ hit = true;
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
+ hit = true;
if (hit) {
- if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- wPoint->velocity = 0.0f;
- }
- else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE)
- wPoint->velocity = isect_height;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT)
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) {
- if (isect_change < 0.0f)
- wPoint->height += isect_change * brush->wave_factor;
+ switch (brush->wave_type) {
+ case MOD_DPAINT_WAVEB_DEPTH:
+ wPoint->height = isect_height;
+ wPoint->state = DPAINT_WAVE_OBSTACLE;
+ wPoint->velocity = 0.0f;
+ break;
+ case MOD_DPAINT_WAVEB_FORCE:
+ wPoint->velocity = isect_height;
+ break;
+ case MOD_DPAINT_WAVEB_REFLECT:
+ wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
+ break;
+ case MOD_DPAINT_WAVEB_CHANGE:
+ if (isect_change < 0.0f)
+ wPoint->height += isect_change * wave_factor;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
}
}
@@ -2903,8 +3171,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(
+ const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush,
+ float paint[3], float influence, float depth, float vel_factor, const float timescale)
{
PaintSurfaceData *sData = surface->data;
float strength;
@@ -2924,9 +3193,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];
@@ -2937,12 +3204,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);
-
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
}
/* displace surface */
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -2957,10 +3222,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 */
@@ -2969,10 +3234,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 */
@@ -2981,8 +3246,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 */
@@ -2992,19 +3256,57 @@ 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)
+typedef struct DynamicPaintBrushVelocityData {
+ Vec3f *brush_vel;
+
+ const MVert *mvert_p;
+ const MVert *mvert_c;
+
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
+
+ const float timescale;
+} DynamicPaintBrushVelocityData;
+
+static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i)
+{
+ const DynamicPaintBrushVelocityData *data = userdata;
+
+ Vec3f *brush_vel = data->brush_vel;
+
+ const MVert *mvert_p = data->mvert_p;
+ const MVert *mvert_c = data->mvert_c;
+
+ float (*obmat)[4] = data->obmat;
+ float (*prev_obmat)[4] = data->prev_obmat;
+
+ const float timescale = data->timescale;
+
+ float p1[3], p2[3];
+
+ copy_v3_v3(p1, mvert_p[i].co);
+ mul_m4_v3(prev_obmat, p1);
+
+ copy_v3_v3(p2, mvert_c[i].co);
+ mul_m4_v3(obmat, p2);
+
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+}
+
+static void dynamicPaint_brushMeshCalculateVelocity(
+ Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
- int i;
float prev_obmat[4][4];
DerivedMesh *dm_p, *dm_c;
MVert *mvert_p, *mvert_c;
@@ -3024,7 +3326,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);
@@ -3034,33 +3337,27 @@ 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 */
+ /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
if (numOfVerts_p != numOfVerts_c)
mvert_p = mvert_c;
/* calculate speed */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < numOfVerts_c; i++) {
- float p1[3], p2[3];
-
- copy_v3_v3(p1, mvert_p[i].co);
- mul_m4_v3(prev_obmat, p1);
-
- copy_v3_v3(p2, mvert_c[i].co);
- mul_m4_v3(ob->obmat, p2);
-
- sub_v3_v3v3((*brushVel)[i].v, p2, p1);
- mul_v3_fl((*brushVel)[i].v, 1.0f / timescale);
- }
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000);
dm_p->release(dm_p);
}
@@ -3084,13 +3381,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);
@@ -3100,9 +3399,365 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
mul_v3_fl(brushVel->v, 1.0f / timescale);
}
+typedef struct DynamicPaintPaintData {
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const BrushMaterials *bMats;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ DerivedMesh *dm;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const float brush_radius;
+ const float *avg_brushNor;
+ const Vec3f *brushVelocity;
+
+ const float solidradius;
+
+ void *treeData;
+
+ float *pointCoord;
+} DynamicPaintPaintData;
+
/*
* Paint a brush object mesh to the surface
*/
+static void dynamic_paint_paint_mesh_cell_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
+
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ DerivedMesh *dm = data->dm;
+ const MVert *mvert = data->mvert;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const float brush_radius = data->brush_radius;
+ const float *avg_brushNor = data->avg_brushNor;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ BVHTreeFromMesh *treeData = data->treeData;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ const int samples = bData->s_num[index];
+ int ss;
+ float total_sample = (float)samples;
+ float brushStrength = 0.0f; /* brush influence factor */
+ float depth = 0.0f; /* brush intersection depth */
+ float velocity_val = 0.0f;
+
+ float paintColor[3] = {0.0f};
+ int numOfHits = 0;
+
+ /* for image sequence anti-aliasing, use gaussian factors */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ total_sample = gaussianTotal;
+
+ /* Supersampling */
+ for (ss = 0; ss < samples; ss++) {
+ float ray_start[3], ray_dir[3];
+ float sample_factor = 0.0f;
+ float sampleStrength = 0.0f;
+ BVHTreeRayHit hit;
+ BVHTreeNearest nearest;
+ short hit_found = 0;
+
+ /* volume sample */
+ float volume_factor = 0.0f;
+ /* proximity sample */
+ float proximity_factor = 0.0f;
+ float prox_colorband[4] = {0.0f};
+ const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
+ brush->collision == MOD_DPAINT_COL_VOLDIST);
+
+ /* hit data */
+ float hitCoord[3];
+ int hitTri = -1;
+
+ /* Supersampling factor */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ sample_factor = gaussianFactors[ss];
+ else
+ sample_factor = 1.0f;
+
+ /* Get current sample position in world coordinates */
+ copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
+ copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
+
+ /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
+ add_v3_fl(ray_start, 0.001f);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
+ 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 */
+ const int vtri[3] = {
+ mloop[mlooptri[hit.index].tri[0]].v,
+ mloop[mlooptri[hit.index].tri[1]].v,
+ mloop[mlooptri[hit.index].tri[2]].v,
+ };
+ float dot;
+
+ normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
+ dot = dot_v3v3(ray_dir, hit.no);
+
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0.0f) {
+ const float dist = hit.dist;
+ const int f_index = hit.index;
+
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two brush faces */
+ negate_v3(ray_dir);
+ 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);
+
+ if (hit.index != -1) {
+ /* Add factor on supersample filter */
+ volume_factor = 1.0f;
+ hit_found = HIT_VOLUME;
+
+ /* Mark hit info */
+ madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+ depth += dist * sample_factor;
+ hitTri = f_index;
+ }
+ }
+ }
+ }
+
+ /* Check proximity collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
+ (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
+ {
+ float proxDist = -1.0f;
+ float hitCo[3] = {0.0f, 0.0f, 0.0f};
+ int tri = 0;
+
+ /* if inverse prox and no hit found, skip this sample */
+ if (inner_proximity && !hit_found)
+ continue;
+
+ /* If pure distance proximity, find the nearest point on the mesh */
+ if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
+ 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;
+ }
+ }
+ else { /* else cast a ray in defined projection direction */
+ float proj_ray[3] = {0.0f};
+
+ if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
+ copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
+ negate_v3(proj_ray);
+ }
+ else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
+ copy_v3_v3(proj_ray, avg_brushNor);
+ }
+ else { /* MOD_DPAINT_RAY_ZPLUS */
+ proj_ray[2] = 1.0f;
+ }
+ hit.index = -1;
+ hit.dist = brush_radius;
+
+ /* Do a face normal directional raycast, and use that distance */
+ 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;
+ }
+ }
+
+ /* If a hit was found, calculate required values */
+ if (proxDist >= 0.0f && proxDist <= brush_radius) {
+ proximity_factor = proxDist / brush_radius;
+ CLAMP(proximity_factor, 0.0f, 1.0f);
+ if (!inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+
+ hit_found = HIT_PROXIMITY;
+
+ /* if no volume hit, use prox point face info */
+ if (hitTri == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitTri = tri;
+ }
+ }
+ }
+
+ /* 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)
+ {
+ volume_factor = 1.0f - volume_factor;
+ if (inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+ }
+
+ /* apply final sample depending on final hit type */
+ if (hit_found == HIT_VOLUME) {
+ sampleStrength = volume_factor;
+ }
+ 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))
+ {
+ proximity_factor = prox_colorband[3];
+ }
+ 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;
+ }
+
+ sampleStrength *= sample_factor;
+ }
+ else {
+ continue;
+ }
+
+ /* velocity brush, only do on main sample */
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
+ float weights[4];
+ float brushPointVelocity[3];
+ float velocity[3];
+
+ const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
+ const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
+ const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
+
+ /* calculate barycentric weights for hit point */
+ interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+
+ /* simple check based on brush surface velocity,
+ * todo: perhaps implement something that handles volume movement as well */
+
+ /* interpolate vertex speed vectors to get hit point velocity */
+ interp_v3_v3v3v3(brushPointVelocity,
+ brushVelocity[v1].v,
+ brushVelocity[v2].v,
+ brushVelocity[v3].v, weights);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushPointVelocity);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* if brush has smudge enabled store 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);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ /*
+ * Process hit color and alpha
+ */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float sampleColor[3];
+ float alpha_factor = 1.0f;
+
+ sampleColor[0] = brush->r;
+ sampleColor[1] = brush->g;
+ 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, dm);
+ }
+
+ /* Sample proximity colorband if required */
+ 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];
+ sampleColor[2] = prox_colorband[2];
+ }
+ }
+
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
+ sampleStrength *= alpha_factor;
+ numOfHits++;
+ }
+
+ /* apply sample strength */
+ brushStrength += sampleStrength;
+ } // end supersampling
+
+
+ /* if any sample was inside paint range */
+ if (brushStrength > 0.0f || depth > 0.0f) {
+ /* apply supersampling results */
+ if (samples > 1) {
+ brushStrength /= total_sample;
+ }
+ CLAMP(brushStrength, 0.0f, 1.0f);
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ }
+ /* get final object space depth */
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ depth /= bData->bNormal[index].normal_scale * total_sample;
+ }
+
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ }
+}
+
static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
@@ -3121,11 +3776,13 @@ 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};
- float brush_radius = brush->paint_distance * surface->radius_scale;
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
int numOfVerts;
int ii;
Bounds3D mesh_bb = {0};
@@ -3172,305 +3829,25 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- 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)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- int ss, samples = bData->s_num[index];
- float total_sample = (float)samples;
- float brushStrength = 0.0f; /* brush influence factor */
- float depth = 0.0f; /* brush intersection depth */
- float velocity_val = 0.0f;
-
- float paintColor[3] = {0.0f};
- int numOfHits = 0;
-
- /* for image sequence anti-aliasing, use gaussian factors */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- total_sample = gaussianTotal;
-
- /* Supersampling */
- for (ss = 0; ss < samples; ss++) {
-
- float ray_start[3], ray_dir[3];
- float sample_factor = 0.0f;
- float sampleStrength = 0.0f;
- BVHTreeRayHit hit;
- BVHTreeNearest nearest;
- short hit_found = 0;
-
- /* volume sample */
- float volume_factor = 0.0f;
- /* proximity sample */
- float proximity_factor = 0.0f;
- float prox_colorband[4] = {0.0f};
- int inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
- brush->collision == MOD_DPAINT_COL_VOLDIST);
-
- /* hit data */
- float hitCoord[3];
- int hitTri = -1;
-
- /* Supersampling factor */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- sample_factor = gaussianFactors[ss];
- else
- sample_factor = 1.0f;
-
- /* Get current sample position in world coordinates */
- copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
- copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
-
- /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
- add_v3_fl(ray_start, 0.001f);
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- nearest.index = -1;
- nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
-
- /* 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) {
- /* 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 */
- const int vtri[3] = {
- mloop[mlooptri[hit.index].tri[0]].v,
- mloop[mlooptri[hit.index].tri[1]].v,
- mloop[mlooptri[hit.index].tri[2]].v,
- };
- float dot;
-
- normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- dot = dot_v3v3(ray_dir, hit.no);
-
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- float dist = hit.dist;
- int f_index = hit.index;
-
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two brush faces */
- negate_v3(ray_dir);
- 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);
-
- if (hit.index != -1) {
- /* Add factor on supersample filter */
- volume_factor = 1.0f;
- hit_found = HIT_VOLUME;
-
- /* Mark hit info */
- madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
- depth += dist * sample_factor;
- hitTri = f_index;
- }
- }
- }
-
- /* Check proximity collision */
- if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) &&
- (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
- {
- float proxDist = -1.0f;
- float hitCo[3] = {0.0f, 0.0f, 0.0f};
- int tri = 0;
-
- /* if inverse prox and no hit found, skip this sample */
- if (inner_proximity && !hit_found) continue;
-
- /* 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) {
- proxDist = sqrtf(nearest.dist_sq);
- copy_v3_v3(hitCo, nearest.co);
- tri = nearest.index;
- }
- }
- else { /* else cast a ray in defined projection direction */
- float proj_ray[3] = {0.0f};
-
- if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
- copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
- negate_v3(proj_ray);
- }
- else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
- copy_v3_v3(proj_ray, avg_brushNor);
- }
- else { /* MOD_DPAINT_RAY_ZPLUS */
- proj_ray[2] = 1.0f;
- }
- hit.index = -1;
- 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) {
- proxDist = hit.dist;
- madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
- tri = hit.index;
- }
- }
-
- /* If a hit was found, calculate required values */
- if (proxDist >= 0.0f && proxDist <= brush_radius) {
- proximity_factor = proxDist / brush_radius;
- CLAMP(proximity_factor, 0.0f, 1.0f);
- if (!inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
-
- hit_found = HIT_PROXIMITY;
-
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
-
- /* 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) {
- volume_factor = 1.0f - volume_factor;
- if (inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
- }
-
- /* apply final sample depending on final hit type */
- if (hit_found == HIT_VOLUME) {
- sampleStrength = volume_factor;
- }
- 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))
- proximity_factor = prox_colorband[3];
- 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;
- }
-
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
-
- /* velocity brush, only do on main sample */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- int v1, v2, v3;
- float weights[4];
- float brushPointVelocity[3];
- float velocity[3];
-
- v1 = mloop[mlooptri[hitTri].tri[0]].v;
- v2 = mloop[mlooptri[hitTri].tri[1]].v;
- v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
-
- /* simple check based on brush surface velocity,
- * todo: perhaps implement something that handles volume movement as well */
-
- /* interpolate vertex speed vectors to get hit point velocity */
- interp_v3_v3v3v3(brushPointVelocity,
- brushVelocity[v1].v,
- brushVelocity[v2].v,
- brushVelocity[v3].v, weights);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushPointVelocity);
- }
- velocity_val = len_v3(velocity);
-
- /* if brush has smudge enabled store 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);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- /*
- * Process hit color and alpha
- */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float sampleColor[3];
- float alpha_factor = 1.0f;
-
- sampleColor[0] = brush->r;
- sampleColor[1] = brush->g;
- 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);
-
- /* Sample proximity colorband if required */
- 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];
- sampleColor[2] = prox_colorband[2];
- }
- }
-
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
-
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
-
-
- /* if any sample was inside paint range */
- if (brushStrength > 0.0f || depth > 0.0f) {
-
- /* apply supersampling results */
- if (samples > 1) {
- brushStrength /= total_sample;
- }
- CLAMP(brushStrength, 0.0f, 1.0f);
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- }
- /* get final object space depth */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
- }
- }
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale, .c_index = c_index,
+ .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
+ .treeData = &treeData
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
}
}
}
@@ -3488,110 +3865,142 @@ static int dynamicPaint_paintMesh(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 void dynamic_paint_paint_single_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
{
- int index;
- float brush_radius = brush->paint_distance * surface->radius_scale;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Vec3f brushVel;
+ const DynamicPaintPaintData *data = userdata;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
- /*
- * Loop through every surface point
- */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
- if (distance > brush_radius) continue;
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
- /* Smooth range or color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
- {
- strength = 1.0f - distance / brush_radius;
- CLAMP(strength, 0.0f, 1.0f);
- }
- else {
- strength = 1.0f;
- }
+ const MVert *mvert = data->mvert;
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
+ float *pointCoord = data->pointCoord;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- MVert *mvert = brush->dm->getVertArray(brush->dm);
- /* use dummy coord of first vertex */
- 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);
- }
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
- strength = colorband[3];
+ if (distance > brush_radius)
+ return;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
+ {
+ strength = 1.0f - distance / brush_radius;
+ CLAMP(strength, 0.0f, 1.0f);
+ }
+ else {
+ strength = 1.0f;
+ }
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVel.v);
- }
- velocity_val = len_v3(velocity);
+ if (strength >= 0.001f) {
+ float paintColor[3] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
- /* store brush velocity for smudge */
- 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);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
+ /* material */
+ if (brush_usesMaterial(brush, scene)) {
+ float alpha_factor = 1.0f;
+ float hit_coord[3];
+ /* use dummy coord of first vertex */
+ mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
+
+ 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))
+ {
+ strength = colorband[3];
+ }
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
+ float velocity[3];
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushVelocity->v);
}
+ velocity_val = len_v3(velocity);
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
- {
- paintColor[0] = colorband[0];
- paintColor[1] = colorband[1];
- paintColor[2] = colorband[2];
- }
- else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
+ /* store brush velocity for smudge */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
+ brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
+ {
+ mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
{
- /* 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;
+ paintColor[0] = colorband[0];
+ paintColor[1] = colorband[1];
+ paintColor[2] = colorband[2];
+ }
+ else {
+ if (!brush_usesMaterial(brush, scene)) {
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
+ }
}
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
+ depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+}
+
+static int dynamicPaint_paintSinglePoint(
+ DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+{
+ PaintSurfaceData *sData = surface->data;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
+ Vec3f brushVel;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+
+ const MVert *mvert = brush->dm->getVertArray(brush->dm);
+
+ /*
+ * Loop through every surface point
+ */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius, .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
+ dynamic_paint_paint_single_point_cb_ex,
+ sData->total_points > 1000, true);
return 1;
}
@@ -3602,57 +4011,68 @@ 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 dynamic_paint_prepare_adjacency_cb(void *userdata, const int index)
+{
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
+
+ const int num_neighs = adj_data->n_num[index];
+
+ for (int i = 0; i < num_neighs; i++) {
+ const int n_index = adj_data->n_index[index] + i;
+ const int t_index = adj_data->n_target[n_index];
+
+ /* dir vec */
+ sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
+ /* dist */
+ bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
+ }
+}
+
+static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
BakeAdjPoint *bNeighs;
PaintAdjData *adj_data = sData->adj_data;
- Vec3f *realCoord = bData->realCoord;
- int index;
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return;
+ int index;
- 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 ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = adj_data->n_num[index];
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
+ if (!bNeighs)
+ return;
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = adj_data->n_index[index] + i;
- int t_index = adj_data->n_target[n_index];
-
- /* dir vec */
- sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
- /* 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);
- }
- }
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000);
- /* calculate average values (single thread) */
- bData->average_dist = 0.0f;
+ /* calculate average values (single thread).
+ * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
+ bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
- int i;
int numOfNeighs = adj_data->n_num[index];
- for (i = 0; i < numOfNeighs; i++) {
+ for (int i = 0; i < numOfNeighs; i++) {
bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
}
}
- bData->average_dist /= adj_data->total_targets;
+ bData->average_dist /= adj_data->total_targets;
}
/* 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(
+ const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
{
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int numOfNeighs = sData->adj_data->n_num[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
int i;
closest_id[0] = closest_id[1] = -1;
@@ -3660,35 +4080,42 @@ static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int inde
/* find closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const int n_index = sData->adj_data->n_index[index] + i;
+ const 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++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+ const int n_index = sData->adj_data->n_index[index] + i;
- if (n_index == closest_id[0]) continue;
+ if (n_index == closest_id[0])
+ continue;
+
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
/* 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 */
if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
- closest_d[1] = dir_dot; closest_id[1] = n_index;
+ closest_d[1] = dir_dot;
+ closest_id[1] = n_index;
}
}
- /* if two valid neighs found, calculate how force effect is divided
- * evenly between them (so that d[0]+d[1] = 1.0)*/
+ /* if two valid neighs found, calculate how force effect is divided evenly between them
+ * (so that d[0] + d[1] = 1.0) */
if (closest_id[1] != -1) {
float force_proj[3];
float tangent[3];
- float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
float force_intersect;
float temp;
@@ -3725,12 +4152,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);
@@ -3738,7 +4166,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];
@@ -3748,8 +4175,9 @@ 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);
@@ -3762,7 +4190,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);
@@ -3781,11 +4210,83 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
}
}
+typedef struct DynamicPaintEffectData {
+ const DynamicPaintSurface *surface;
+ Scene *scene;
+
+ float *force;
+ ListBase *effectors;
+ const void *prevPoint;
+ const float eff_scale;
+
+ uint8_t *point_locks;
+
+ const float wave_speed;
+ const float wave_scale;
+ const float wave_max_slope;
+
+ const float dt;
+ const float min_dist;
+ const float damp_factor;
+ const bool reset_wave;
+} DynamicPaintEffectData;
+
/*
* 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 void dynamic_paint_prepare_effect_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ Vec3f *realCoord = bData->realCoord;
+
+ Scene *scene = data->scene;
+
+ float *force = data->force;
+ ListBase *effectors = data->effectors;
+
+ float forc[3] = {0};
+ float vel[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0) */
+ madd_v3_v3fl(forc, scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
+
+ /* add surface point velocity and acceleration if enabled */
+ if (bData->velocity) {
+ if (surface->drip_vel)
+ madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
+
+ /* acceleration */
+ if (bData->prev_velocity && surface->drip_acc) {
+ float acc[3];
+ copy_v3_v3(acc, bData->velocity[index].v);
+ sub_v3_v3(acc, bData->prev_velocity[index].v);
+ madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
+ }
+ }
+
+ /* force strength, and normalize force vec */
+ force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
+}
+
+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;
@@ -3793,60 +4294,24 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
int steps;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
- int index;
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- float vel[3] = {0};
ListBase *effectors = pdInitEffectors(scene, ob, surface->effector_weights, true);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
if (*force) {
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float forc[3] = {0};
-
- /* apply force fields */
- if (effectors) {
- EffectedPoint epoint;
- pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
- epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
- }
-
- /* if global gravity is enabled, add it too */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
- /* also divide by 10 to about match default grav
- * with default force strength (1.0) */
- madd_v3_v3fl(forc, scene->physics_settings.gravity,
- surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
-
- /* add surface point velocity and acceleration if enabled */
- if (bData->velocity) {
- if (surface->drip_vel)
- madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
-
- /* acceleration */
- if (bData->prev_velocity && surface->drip_acc) {
- float acc[3];
- copy_v3_v3(acc, bData->velocity[index].v);
- sub_v3_v3(acc, bData->prev_velocity[index].v);
- madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
- }
- }
-
- /* 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]);
- copy_v3_v3(&((*force)[index * 4]), forc);
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .scene = scene,
+ .force = *force, .effectors = effectors,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000);
/* calculate average values (single thread) */
- for (index = 0; index < sData->total_points; index++) {
+ for (int index = 0; index < sData->total_points; index++) {
average_force += (*force)[index * 4 + 3];
}
average_force /= sData->total_points;
@@ -3866,7 +4331,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
- steps = (int)ceil(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
CLAMP(steps, 1, 20);
return steps;
@@ -3875,166 +4340,337 @@ 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 dynamic_paint_effect_spread_cb(void *userdata, const int index)
{
- PaintSurfaceData *sData = surface->data;
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- int index;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float w_factor;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const float color_mix = min_fff(pPoint_prev->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], pPoint_prev->e_color, pPoint_prev->e_color[3], color_mix);
+
+ /* Only continue if surrounding point has higher wetness */
+ if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
+ continue;
+
+ w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->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 * pPoint_prev->wetness;
+ pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
+ pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
+ }
+}
+
+static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+ float totalAlpha = 0.0f;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += pPoint_prev->e_color[3];
+
+ /* 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;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs * (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale, 0.0f);
+ /* decrease factor for wet paint alpha */
+ ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 * (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale, 0.0f);
+ /* decrease factor for paint wetness */
+ w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 * (pPoint->wetness - pPoint_prev->wetness) * speed_scale, 0.0f);
+
+ pPoint->color[3] -= a_factor;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ pPoint->e_color[3] -= ea_factor;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->wetness -= w_factor;
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+ }
+}
+
+static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_target = sData->adj_data->n_target;
+
+ uint8_t *point_locks = data->point_locks;
+
+ int closest_id[2];
+ float closest_d[2];
+
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
+
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more eficient than a global spin lock. */
+ const unsigned int pointlock_idx = n_trgt / 8;
+ const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
+
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
+
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
+
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
+
+ /* 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);
+ /* 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];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
+
+ /* decrease paint wetness on current point */
+ pPoint->wetness -= (ePoint->wetness - e_wet);
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+
+#ifndef NDEBUG
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+ BLI_assert(ret & pointlock_bitmask);
+#else
+ atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+#endif
+ }
+ }
+}
+
+static void dynamicPaint_doEffectStep(
+ DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
timescale /= steps;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/*
* Spread Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- /* Only reads values from the surface copy (prevPoint[]),
- * so this one is thread safe */
-
- /* Loop through neighboring points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float w_factor;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- 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);
-
- /* Only continue if surrounding point has higher wetness */
- 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);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000);
}
/*
* Shrink Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- float totalAlpha = 0.0f;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += ePoint->e_color[3];
-
- /* 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;
-
- /* decrease factor for dry paint alpha */
- a_factor = (1.0f - ePoint->color[3]) / numOfNeighs * (pPoint->color[3] - ePoint->color[3]) * speed_scale;
- CLAMP_MIN(a_factor, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = (1.0f - ePoint->e_color[3]) / 8 * (pPoint->e_color[3] - ePoint->e_color[3]) * speed_scale;
- CLAMP_MIN(ea_factor, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = (1.0f - ePoint->wetness) / 8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
- CLAMP_MIN(w_factor, 0.0f);
-
- pPoint->color[3] -= a_factor;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- pPoint->e_color[3] -= ea_factor;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->wetness -= w_factor;
- CLAMP_MIN(pPoint->wetness, 0.0f);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000);
}
/*
* Drip Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+
+ /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
+ const size_t point_locks_size = (sData->total_points / 8) + 1;
+ uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
+
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
- for (index = 0; index < sData->total_points; index++) {
- int i;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- PaintPoint *pPoint_prev = &prevPoint[index];
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .eff_scale = eff_scale, .force = force,
+ .point_locks = point_locks,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000);
- int closest_id[2];
- float closest_d[2];
+ MEM_freeN(point_locks);
+ }
+}
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0) continue;
- CLAMP(w_factor, 0.0f, 1.0f);
+static void dynamic_paint_wave_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
- /* Apply movement towards those two points */
- for (i = 0; i < 2; i++) {
- int n_index = closest_id[i];
- if (n_index != -1 && closest_d[i] > 0.0f) {
- float dir_dot = closest_d[i], dir_factor, a_factor;
- float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_index].dist;
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
- float e_wet = ePoint->wetness;
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
-
- dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
- CLAMP_MAX(dir_factor, 0.5f);
-
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
-
- /* 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);
- /* 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];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
- }
- }
+ PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
+ int numOfN = 0, numOfRN = 0;
+
+ if (wPoint->state > 0)
+ return;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+ const int *adj_flags = sData->adj_data->flags;
+
+ /* calculate force from surrounding points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float dist = bNeighs[n_idx].dist * wave_scale;
+ const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
+
+ if (!dist || tPoint->state > 0)
+ continue;
+
+ CLAMP_MIN(dist, min_dist);
+ avg_dist += dist;
+ numOfN++;
+
+ /* count average height for edge points for open borders */
+ if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
+ avg_n_height += tPoint->height;
+ numOfRN++;
+ }
+
+ force += (tPoint->height - wPoint->height) / (dist * dist);
+ avg_height += tPoint->height;
+ }
+ avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+
+ if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
+ /* 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);
+ }
+ /* else do wave eq */
+ else {
+ /* add force towards zero height based on average dist */
+ if (avg_dist)
+ force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
+
+ /* change point velocity */
+ wPoint->velocity += force * dt * wave_speed * wave_speed;
+ /* damping */
+ wPoint->velocity *= damp_factor;
+ /* and new height */
+ wPoint->height += wPoint->velocity * dt;
+
+ /* limit wave slope steepness */
+ if (wave_max_slope && avg_dist) {
+ const float max_offset = wave_max_slope * avg_dist;
+ const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ else if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
}
}
+
+ if (data->reset_wave) {
+ /* if there wasnt any brush intersection, clear isect height */
+ if (wPoint->state == DPAINT_WAVE_NONE) {
+ wPoint->brush_isect = 0.0f;
+ }
+ wPoint->state = DPAINT_WAVE_NONE;
+ }
}
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
@@ -4044,15 +4680,16 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int index;
int steps, ss;
float dt, min_dist, damp_factor;
- float wave_speed = surface->wave_speed;
- float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
+ const float wave_speed = surface->wave_speed;
+ const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
double average_dist = 0.0f;
const float canvas_size = getSurfaceDimension(sData);
- float wave_scale = CANVAS_REL_SIZE / canvas_size;
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
/* 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++) {
@@ -4076,170 +4713,120 @@ 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));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- int numOfNeighs = sData->adj_data->n_num[index];
- float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
- int numOfN = 0, numOfRN = 0;
- int i;
-
- if (wPoint->state > 0) continue;
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
+ .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000);
+ }
- /* calculate force from surrounding points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dist = bNeighs[n_index].dist * wave_scale;
- PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
+ MEM_freeN(prevPoint);
+}
- if (!dist || tPoint->state > 0) continue;
- if (dist < min_dist) dist = min_dist;
- avg_dist += dist;
- numOfN++;
+/* Do dissolve and fading effects */
+static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
+{
+ return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
+ (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
+ (surface->flags & MOD_DPAINT_DISSOLVE)));
+}
- /* count average height for edge points for open borders */
- if (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
+typedef struct DynamicPaintDissolveDryData {
+ const DynamicPaintSurface *surface;
+ const float timescale;
+} DynamicPaintDissolveDryData;
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintDissolveDryData *data = userdata;
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
- sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE)
- {
- /* 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);
- }
- /* else do wave eq */
- else {
- /* add force towards zero height based on average dist */
- if (avg_dist)
- force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
-
- /* change point velocity */
- wPoint->velocity += force * dt * wave_speed * wave_speed;
- /* damping */
- wPoint->velocity *= damp_factor;
- /* and new height */
- wPoint->height += wPoint->velocity * dt;
-
- /* limit wave slope steepness */
- 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;
- }
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
- /* reset state */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- /* if there wasnt any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ /* drying */
+ if (surface->flags & MOD_DPAINT_USE_DRYING) {
+ if (pPoint->wetness >= MIN_WETNESS) {
+ 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) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
- MEM_freeN(prevPoint);
-}
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
-/* Do dissolve and fading effects */
-static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale)
-{
- PaintSurfaceData *sData = surface->data;
- int index;
+ /*
+ * Slowly "shift" paint from wet layer to dry layer as it drys:
+ */
+ /* make sure alpha values are within proper range */
+ CLAMP(pPoint->color[3], 0.0f, 1.0f);
+ CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- /* Do drying dissolve effects */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- /* drying */
- if (surface->flags & MOD_DPAINT_USE_DRYING) {
- if (pPoint->wetness >= MIN_WETNESS) {
- 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;
-
- if (pPoint->wetness < surface->color_dry_threshold) {
- dry_ratio = pPoint->wetness / p_wetness;
-
- /*
- * Slowly "shift" paint from wet layer to dry layer as it drys:
- */
- /* make sure alpha values are within proper range */
- CLAMP(pPoint->color[3], 0.0f, 1.0f);
- CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-
- /* get current final blended color of these layers */
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- /* reduce wet layer alpha by dry factor */
- pPoint->e_color[3] *= dry_ratio;
-
- /* now calculate new alpha for dry layer that keeps final blended color unchanged */
- pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
- /* for each rgb component, calculate a new dry layer color that keeps the final blend color
- * 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]));
- }
+ /* get current final blended color of these layers */
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ /* reduce wet layer alpha by dry factor */
+ pPoint->e_color[3] *= dry_ratio;
+
+ /* now calculate new alpha for dry layer that keeps final blended color unchanged */
+ pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
+ /* for each rgb component, calculate a new dry layer color that keeps the final blend color
+ * 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->state = DPAINT_PAINT_WET;
}
- /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
- else if (pPoint->state > 0) {
- float f_color[4];
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- copy_v4_v4(pPoint->color, f_color);
- /* clear wet layer */
- pPoint->wetness = 0.0f;
- pPoint->e_color[3] = 0.0f;
- pPoint->state = DPAINT_PAINT_DRY;
- }
- }
- if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->color[3], 0.0f);
-
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->state = DPAINT_PAINT_WET;
+ }
+ /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
+ else if (pPoint->state > 0) {
+ float f_color[4];
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ copy_v4_v4(pPoint->color, f_color);
+ /* clear wet layer */
+ pPoint->wetness = 0.0f;
+ pPoint->e_color[3] = 0.0f;
+ pPoint->state = DPAINT_PAINT_DRY;
}
}
- /* 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))
- {
- float *point = &((float *)sData->type_data)[index];
- /* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(*point, 0.0f);
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
+ 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) != 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))
+ {
+ float *point = &((float *)sData->type_data)[index];
+ /* log or linear */
+ 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;
@@ -4248,67 +4835,159 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
int numOfVerts = dm->getNumVerts(dm);
int i;
- int ret = 0;
- 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)) {
+ return true;
+ }
}
- return ret;
+ return false;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
-{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+/* Prepare for surface step by creating PaintBakeNormal data */
+typedef struct DynamicPaintGenerateBakeData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
- if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)
- return 1;
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
- return 0;
-}
+ const bool do_velocity_data;
+ const bool new_bdata;
+} DynamicPaintGenerateBakeData;
-static int surface_needsAccelerationData(DynamicPaintSurface *surface)
+static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+ const DynamicPaintGenerateBakeData *data = userdata;
- return 0;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintAdjData *adj_data = sData->adj_data;
+ const PaintBakeData *bData = sData->bData;
+
+ Object *ob = data->ob;
+
+ const MVert *mvert = data->mvert;
+ const Vec3f *canvas_verts = data->canvas_verts;
+
+ const bool do_velocity_data = data->do_velocity_data;
+ const bool new_bdata = data->new_bdata;
+
+ float prev_point[3] = {0.0f, 0.0f, 0.0f};
+ float temp_nor[3];
+
+ if (do_velocity_data && !new_bdata) {
+ copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
+ }
+
+ /*
+ * Calculate current 3D-position and normal of each surface point
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+
+ bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ bData->s_pos[index] = index * bData->s_num[index];
+
+ /* per sample coordinates */
+ for (int ss = 0; ss < bData->s_num[index]; ss++) {
+ interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v,
+ f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
+ }
+
+ /* Calculate current pixel surface normal */
+ 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);
+ normalize_v3(temp_nor);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int ss;
+ if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
+ bData->s_num[index] = adj_data->n_num[index] + 1;
+ bData->s_pos[index] = adj_data->n_index[index] + index;
+ }
+ else {
+ bData->s_num[index] = 1;
+ bData->s_pos[index] = index;
+ }
+
+ /* calculate position for each sample */
+ for (ss = 0; ss < bData->s_num[index]; ss++) {
+ /* first sample is always point center */
+ copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
+ if (ss > 0) {
+ 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);
+ }
+ }
+
+ /* normal */
+ normal_short_to_float_v3(temp_nor, mvert[index].no);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+
+ /* calculate speed vector */
+ if (do_velocity_data && !new_bdata && !bData->clear) {
+ sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
+ }
}
-/* Prepare for surface step by creating PaintBakeNormal data */
static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
- PaintAdjData *adj_data = sData->adj_data;
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);
+ int index;
+ bool new_bdata = false;
+ 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)
@@ -4324,13 +5003,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;
}
@@ -4343,16 +5024,21 @@ 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"));
}
- new_bdata = 1;
+ new_bdata = true;
}
if (do_velocity_data && !bData->velocity) {
@@ -4368,7 +5054,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- bData->mesh_bounds.valid = 0;
+ bData->mesh_bounds.valid = false;
for (index = 0; index < canvasNumOfVerts; index++) {
copy_v3_v3(canvas_verts[index].v, mvert[index].co);
mul_m4_v3(ob->obmat, canvas_verts[index].v);
@@ -4378,112 +5064,20 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Prepare each surface point for a new step
*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- if (do_velocity_data && !new_bdata) {
- copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
- }
- /*
- * Calculate current 3D-position and normal of each surface point
- */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- int ss;
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[tPoint->v1].v,
- canvas_verts[tPoint->v2].v,
- canvas_verts[tPoint->v3].v,
- f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
- }
-
- /* Calculate current pixel surface normal */
- 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(bData->bNormal[index].invNorm,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int ss;
- if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
- bData->s_num[index] = adj_data->n_num[index] + 1;
- bData->s_pos[index] = adj_data->n_index[index] + index;
- }
- else {
- bData->s_num[index] = 1;
- bData->s_pos[index] = index;
- }
-
- /* calculate position for each sample */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- /* first sample is always point center */
- copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
- if (ss > 0) {
- 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);
- }
- }
-
- /* normal */
- normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
-
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- float temp_nor[3];
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- normalize_v3(temp_nor);
- }
- else {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- 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);
- }
-
- mul_v3_v3(temp_nor, ob->size);
- bData->bNormal[index].normal_scale = len_v3(temp_nor);
- }
-
- /* calculate speed vector */
- if (do_velocity_data && !new_bdata && !bData->clear) {
- sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
- }
- }
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface, .ob = ob,
+ .mvert = mvert, .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000);
MEM_freeN(canvas_verts);
/* 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);
@@ -4503,9 +5097,16 @@ 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;
- dynamicPaint_surfacePreStep(surface, timescale);
+ if (sData->total_points < 1)
+ return 0;
+
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_surface_pre_step_cb, sData->total_points > 1000);
+ }
+
/*
* Loop through surface's target paint objects and do painting
*/
@@ -4529,24 +5130,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)) {
@@ -4561,15 +5161,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))
@@ -4595,7 +5196,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 */
@@ -4635,8 +5237,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);
}
}
@@ -4655,8 +5259,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
-
+ dynamicPaint_generateBakeData(surface, scene, cObject);
+
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
int st;
@@ -4664,7 +5268,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/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 66e37203dbb..af5089f742f 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -607,13 +607,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/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 d5f9a2dac3e..1ae7ca189fb 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -842,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;
}
@@ -1755,6 +1748,7 @@ typedef struct StampData {
char scene[STAMP_NAME_SIZE];
char strip[STAMP_NAME_SIZE];
char rendertime[STAMP_NAME_SIZE];
+ char memory[STAMP_NAME_SIZE];
} StampData;
#undef STAMP_NAME_SIZE
@@ -1876,6 +1870,13 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
else {
stamp_data->rendertime[0] = '\0';
}
+
+ if (stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
}
@@ -1950,6 +1951,12 @@ static void stampdata_from_template(StampData *stamp_data,
else {
stamp_data->rendertime[0] = '\0';
}
+ if (scene->r.stamp & R_STAMP_MEMORY) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
void BKE_image_stamp_buf(
@@ -2063,6 +2070,21 @@ void BKE_image_stamp_buf(
}
/* Top left corner, below File, Date, Rendertime */
+ if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
+ 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Memory, Rendertime */
BLF_enable(mono, BLF_WORD_WRAP);
if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
y -= h;
@@ -2226,6 +2248,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall
CALL(scene, "Scene");
CALL(strip, "Strip");
CALL(rendertime, "RenderTime");
+ CALL(memory, "Memory");
#undef CALL
}
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 10e7d46b315..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;
@@ -342,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 071071d9d0f..64c9ddb5b38 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1764,7 +1764,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
@@ -1811,9 +1811,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/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index c8bb2e0e758..a472b6e5bc1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -262,6 +262,51 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
}
/**
+ * Generates a map where the key is the edge and the value is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const MVert *UNUSED(mvert), const int totvert,
+ const MLoopTri *mlooptri, const int totlooptri,
+ const MLoop *mloop, const int UNUSED(totloop))
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ int *index_step;
+ const MLoopTri *mlt;
+ int i;
+
+ /* count face users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ map[mloop[mlt->tri[j]].v].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign looptri-edge users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
* The lists are allocated from one memory pool.
*/
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 a3597541529..51bc0b597c7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -232,6 +232,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/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/scene.c b/source/blender/blenkernel/intern/scene.c
index 1a452fbdc96..e06c7a43dd8 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";
@@ -547,7 +542,7 @@ void BKE_scene_init(Scene *sce)
sce->r.bake.im_format.compress = 15;
sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME;
+ sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
sce->r.stamp_font_id = 12;
sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
sce->r.fg_stamp[3] = 1.0f;
@@ -2409,7 +2404,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)
@@ -2440,7 +2434,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 4086fc2b0f3..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,
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 a8e8f10962d..5b6adb3778a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3369,13 +3369,14 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int colType;
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totpoly;
bool flush;
- bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
unsigned int next_actualFace;
unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
int mat_index;
@@ -3394,15 +3395,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
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 45edaca544d..54b824c91ac 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -470,6 +470,10 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
+/********************************* Cubic (Bezier) *******************************/
+
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
+
/**************************** Inline Definitions ******************************/
#if BLI_MATH_DO_INLINE
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 c44fcf47fdb..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;
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 f80099bee1b..370e8bb0035 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -4988,3 +4988,37 @@ int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], con
return ret;
}
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
+{
+ BLI_ASSERT_UNIT_V3(tan_l);
+ BLI_ASSERT_UNIT_V3(tan_r);
+
+ const float eps = 1e-7f;
+ const float tan_dot = dot_v3v3(tan_l, tan_r);
+ if (tan_dot > 1.0f - eps) {
+ /* no angle difference (use fallback, length wont make any difference) */
+ return (1.0f / 3.0f) * 0.75f;
+ }
+ else if (tan_dot < -1.0f + eps) {
+ /* parallele tangents (half-circle) */
+ return (1.0f / 2.0f);
+ }
+ else {
+ /* non-aligned tangents, calculate handle length */
+ const float angle = acosf(tan_dot) / 2.0f;
+
+ /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
+ const float angle_sin = sinf(angle);
+ const float angle_cos = cosf(angle);
+ return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
+ }
+}
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 72a3da265c7..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
@@ -591,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 */
@@ -660,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 e913499ba2b..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>
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index e7938b750da..58475b7f835 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,16 +852,17 @@ 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);
}
for (i = start; i < stop; ++i) {
- func_ex(userdata, userdata_chunk, i, 0);
+ func_ex(userdata, userdata_chunk_local, i, 0);
+ }
+
+ if (func_finalize) {
+ func_finalize(userdata, userdata_chunk_local);
}
MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
@@ -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 5682570b45b..76a16edee49 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4592,6 +4592,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);
@@ -5776,6 +5779,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;
}
}
}
@@ -6544,6 +6552,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
/* render can be quite heavy, set to solid on load */
if (v3d->drawtype == OB_RENDER)
v3d->drawtype = OB_SOLID;
+ v3d->prev_drawtype = OB_SOLID;
if (v3d->fx_settings.dof)
v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b18b2b9fb5f..d6f07545449 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"
@@ -136,6 +137,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)) {
@@ -958,6 +993,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!MAIN_VERSION_ATLEAST(main, 277, 1)) {
+ /* 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) {
@@ -1018,5 +1062,61 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
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/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index a2d1b6a82e8..e7538ec5324 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.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index 218d821913d..7cbfe2d9210 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -52,7 +52,7 @@ struct BMeshFromMeshParams {
void BM_mesh_bm_from_me(
BMesh *bm, struct Mesh *me,
const struct BMeshFromMeshParams *params)
-ATTR_NONNULL(1, 2, 3);
+ATTR_NONNULL(1, 3);
struct BMeshToMeshParams {
unsigned int calc_tessface : 1;
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_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index e3be4db804b..b120b48447f 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -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 1a16bd13fef..ad35d57f35b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -296,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) {
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/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/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_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
index 04bda740068..c29532a02c6 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -246,6 +246,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);
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
index be8a27dfbc1..23d3b391f8a 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -242,6 +242,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...
@@ -1548,7 +1555,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 fb6722cc893..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;
BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
- /* Get context. */
- // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
- /* TODO(sergey): Wedon'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);
-
- /* Note how long this took. */
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
- schedule_children(pool, state->graph, node, state->layers);
+ while (true) {
+ /* Get context. */
+ // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* 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);
+ }
+
+ /* 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;
+ }
+ }
}
-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,13 +317,15 @@ 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)
+ OperationDepsNode *node, bool dec_parents,
+ const int thread_id)
{
int id_layers = node->owner->owner->layers;
@@ -248,19 +338,20 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
}
if (node->num_links_pending == 0) {
- BLI_spin_lock(&graph->lock);
- bool need_schedule = !node->scheduled;
- node->scheduled = true;
- BLI_spin_unlock(&graph->lock);
-
- if (need_schedule) {
+ 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);
+ schedule_children(pool, graph, node, layers, thread_id);
}
else {
/* children are scheduled once this task is completed */
- BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_LOW,
+ thread_id);
}
}
}
@@ -276,30 +367,27 @@ static void schedule_graph(TaskPool *pool,
++it)
{
OperationDepsNode *node = *it;
- schedule_node(pool, graph, layers, node, false);
+ schedule_node(pool, graph, layers, node, false, 0);
}
}
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;
}
-
- schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0);
+ schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id);
}
+ DEPSNODE_RELATIONS_ITER_END;
}
/**
@@ -350,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)
@@ -357,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 4c711bfb8d6..f00bce29f64 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -41,6 +41,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"
@@ -227,6 +229,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)
{
@@ -242,14 +257,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... */
@@ -265,7 +275,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;
}
@@ -310,7 +323,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;
+ }
}
}
@@ -348,23 +364,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();
}
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/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 157aa4cf368..486b2bcd979 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3813,6 +3813,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/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 218f215a350..559d93c7eb1 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,13 @@ 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);
+ }
+ if (pchan_src->bbone_prev) {
+ pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
+ }
+ if (pchan_src->bbone_next) {
+ pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
}
}
}
@@ -682,7 +696,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 +905,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_edit.c b/source/blender/editors/armature/armature_edit.c
index b1c23fb4cac..354b748e129 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -317,9 +317,10 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
float cursor_local[3];
const float *cursor = ED_view3d_cursor3d_get(scene, v3d);
-
+ invert_m4_m4(ob->imat, ob->obmat);
copy_v3_v3(cursor_local, cursor);
- mul_m3_v3(imat, cursor_local);
+ mul_m4_v3(ob->imat, cursor_local);
+
/* cursor */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
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 b62714700fa..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;
-
- p2 = NULL;
- p1->flag = 1;
-
- /* 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);
+ 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));
- if (new_dist < dist) {
- copy_v3_v3(p, vec);
- dist = new_dist;
- size = new_size;
- }
- }
- }
+ float mvalf[2] = {UNPACK2(dd->mval)};
+ float loc[3], dummy_no[3];
- 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,37 +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 */
{
- 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));
-
- found = ED_transform_snap_object_project_view3d_mixed(
+ if (ED_transform_snap_object_project_view3d(
snap_context,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_SELECTED,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_to = ts->snap_mode,
},
- mval, &dist_px, true,
- vec, no);
-
- ED_transform_snap_object_context_destroy(snap_context);
- }
-
- if (found == 1) {
- pt->type = dd->type;
- pt->mode = PT_SNAP;
- copy_v3_v3(pt->p, vec);
+ 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/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index d63616e4f43..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);
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index d1994c8fc15..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);
@@ -262,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 395da2cd2f1..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"
@@ -5776,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
index f17349822c9..bb7cc61f580 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -194,6 +194,8 @@ struct CurveDrawData {
/* offset projection by this value */
bool use_offset;
float offset[3]; /* worldspace */
+ float surface_offset;
+ bool use_surface_offset_absolute;
} project;
/* cursor sampling */
@@ -204,7 +206,6 @@ struct CurveDrawData {
struct {
float min, max, range;
- float offset;
} radius;
struct {
@@ -243,7 +244,10 @@ static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct St
static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure)
{
- if ((cdd->radius.offset != 0.0f) && !is_zero_v3(selem->normal_local)) {
+ 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);
@@ -269,7 +273,7 @@ static void stroke_elem_interp(
static bool stroke_elem_project(
const struct CurveDrawData *cdd,
const int mval_i[2], const float mval_fl[2],
- const float radius_offset, const float radius,
+ float surface_offset, const float radius,
float r_location_world[3], float r_normal_world[3])
{
View3D *v3d = cdd->vc.v3d;
@@ -307,10 +311,11 @@ static bool stroke_elem_project(
zero_v3(r_normal_world);
}
- if (radius_offset != 0.0f) {
+ 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, radius_offset * radius);
+ madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
if (r_normal_world) {
copy_v3_v3(r_normal_world, normal);
}
@@ -333,14 +338,14 @@ static bool stroke_elem_project(
static bool stroke_elem_project_fallback(
const struct CurveDrawData *cdd,
const int mval_i[2], const float mval_fl[2],
- const float radius_offset, const float radius,
+ 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,
- radius_offset, radius,
+ 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);
@@ -372,7 +377,7 @@ static bool stroke_elem_project_fallback_elem(
const float radius = stroke_elem_radius(cdd, selem);
return stroke_elem_project_fallback(
cdd, mval_i, selem->mval,
- cdd->radius.offset, radius,
+ cdd->project.surface_offset, radius,
location_fallback_depth,
selem->location_world, selem->location_local,
selem->normal_world, selem->normal_local);
@@ -480,7 +485,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS
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);
+ gluSphere(qobj, radius, 12, 8);
location_prev = selem->location_local;
}
@@ -637,7 +642,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
/* Special case for when we only have offset applied on the first-hit,
* the remaining stroke must be offset too. */
- if (cdd->radius.offset != 0.0f) {
+ if (cdd->project.surface_offset != 0.0f) {
const float mval_fl[2] = {UNPACK2(event->mval)};
float location_no_offset[3];
@@ -688,7 +693,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
cdd->radius.min = cps->radius_min;
cdd->radius.max = cps->radius_max;
cdd->radius.range = cps->radius_max - cps->radius_min;
- cdd->radius.offset = cps->radius_offset;
+ 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);
@@ -1113,7 +1119,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* 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_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);
plane_no = rv3d->viewinv[2];
cdd->project.use_plane = true;
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 43c82732451..79a2c494239 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) ------ */
@@ -696,7 +850,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 */
@@ -731,7 +885,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... */
@@ -891,7 +1045,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;
@@ -908,13 +1062,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 */
@@ -925,7 +1082,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;
@@ -942,13 +1099,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);
@@ -991,7 +1151,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..0271afd6827 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
@@ -865,14 +866,18 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customda
glTranslatef((float)x, (float)y, 0.0f);
- /* TODO: toggle between add and remove? */
- glColor4ub(255, 255, 255, 128);
-
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
+ /* Inner Ring: Light color for action of the brush */
+ /* TODO: toggle between add and remove? */
+ glColor4ub(255, 255, 255, 200);
glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40);
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ glColor3ub(30, 30, 30);
+ glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40);
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -905,7 +910,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 +1289,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..405b673c42b 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -102,6 +102,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Pie Menu - For standard tools */
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY);
+
+ /* Delete Active Frame - For easier video tutorials/review sessions */
+ /* NOTE: This works even when not in EditMode */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -140,6 +144,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 +194,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);
@@ -191,10 +234,12 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* delete */
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0);
-
+
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
+
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
@@ -229,36 +274,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 +329,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_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f54da91af71..b2c6107ab61 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -641,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_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_transform.h b/source/blender/editors/include/ED_transform.h
index 39df52e5f68..933f480a554 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -158,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,
@@ -179,14 +166,18 @@ 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,
@@ -201,67 +192,4 @@ bool snapNodesContext(
/* return args */
float r_loc[2], float *r_dist_px, char *r_node_border);
-
-/* transform_snap_object.c */
-
-/* ED_transform_snap_object_*** API */
-struct SnapObjectParams {
- SnapSelect snap_select;
- 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);
-
-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_dist,
- float r_co[3], float r_no[3]);
-
-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]);
-
-
#endif /* __ED_TRANSFORM_H__ */
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/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 dd686f18a78..10ab85a6142 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -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
)
{
@@ -7383,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 */
@@ -7391,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;
@@ -7885,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);
@@ -8451,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;
@@ -9823,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 b39ddad5140..0874979e080 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -505,6 +505,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((unsigned char *)cs->solid);
+ glRecti(x, y, a, y + h);
+
+ /* selected */
+ glColor3ubv((unsigned char *)cs->select);
+ glRecti(a, y, b, y + h);
+
+ /* active */
+ glColor3ubv((unsigned char *)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)
@@ -735,6 +792,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);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index e8c1d3df7bf..b7096583376 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2912,7 +2912,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 7d74ad14b61..5098e701638 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -856,10 +856,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);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 3c862666aa6..e2e2413c717 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -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/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 5eaac72590b..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"));
@@ -332,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... */
@@ -373,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.
@@ -383,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;
@@ -395,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 2401b749ab2..1dfb1cddd2c 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -740,7 +740,7 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
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]);
+ RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]);
}
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 097117cce6b..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),
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_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 49794d2e5cd..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"
@@ -5124,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)) {
@@ -5133,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/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 90676d2b951..1b2d4b7c130 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -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_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 a5d2d2c8be7..3d7a45843cc 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -350,6 +350,9 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
return;
}
+ /* Show progress bar. */
+ *(job->do_update) = true;
+
/* Set frame to start point (also inits modifier data) */
frame = surface->start_frame;
orig_frame = scene->r.cfra;
@@ -357,14 +360,15 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
ED_update_for_newframe(job->bmain, scene, 1);
/* Init surface */
- if (!dynamicPaint_createUVSurface(scene, surface)) {
+ if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
job->success = 0;
return;
}
/* Loop through selected frames */
for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
- float progress = (frame - surface->start_frame) / (float)frames;
+ /* The first 10% are for createUVSurface... */
+ const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / (float)frames;
surface->current_frame = frame;
/* If user requested stop, quit baking */
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 3511480821a..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);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index a1c330d9dff..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)
@@ -822,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;
@@ -874,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();
@@ -897,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_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 bce3b46010b..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)
@@ -3647,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);
@@ -3998,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;
@@ -5360,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);
@@ -5867,7 +5866,7 @@ 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,(&(struct BMeshFromMeshParams){
+ bm, me, (&(struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7ebc050978a..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 */
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_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 7f4cd03c2fa..2a3f964f477 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -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_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index effcd80e1f0..f1063996ca3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -693,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");
@@ -782,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 ************************* */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index b6b711e129f..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);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 7ffa8250067..6b860990c10 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -610,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_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 ae5dcc4c73f..8db5a8f9bd3 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -990,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)
{
@@ -2770,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;
@@ -2845,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;
}
@@ -2862,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;
@@ -2895,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);
@@ -2909,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) {
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_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 4abc7f5e71b..d7249897723 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -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 9d1cf65b8ac..09594ab543c 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -423,8 +423,8 @@ static int ui_compatible_sockets(int typeA, int 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;
+ 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);
}
@@ -462,7 +462,7 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
}
NODE_TYPES_END
- qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType*), ui_node_item_name_compare);
+ 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++) {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index cda9de92a82..17b6930e2d9 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;
@@ -899,11 +901,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_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 778ccf902d1..6dce962ee02 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/atomic
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index e3cdedf042b..8ae89941bdb 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1506,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)
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index c197aabedfd..80cb42c0b3d 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -30,11 +30,14 @@
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "atomic_ops.h"
+
#include "sequencer_intern.h"
/* XXX, why is this function better then BLI_math version?
@@ -450,41 +453,57 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
#define HIS_STEPS 512
-static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+typedef struct MakeHistogramViewData {
+ const ImBuf *ibuf;
+ uint32_t (*bins)[HIS_STEPS];
+} MakeHistogramViewData;
+
+static void make_histogram_view_from_ibuf_byte_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int x, y;
- unsigned int nr, ng, nb;
+ MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const unsigned char *src = (unsigned char *)ibuf->rect;
- unsigned int bins[3][HIS_STEPS];
-
- memset(bins, 0, sizeof(bins));
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int x = 0; x < ibuf->x; x++) {
+ const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
- memset(cur_bins, 0, sizeof(cur_bins));
+ for (int j = 3; j--;) {
+ cur_bins[j][pixel[j]]++;
+ }
+ }
+}
- for (x = 0; x < ibuf->x; x++) {
- const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk)
+{
+ MakeHistogramViewData *data = userdata;
+ uint32_t (*bins)[HIS_STEPS] = data->bins;
- cur_bins[0][pixel[0]]++;
- cur_bins[1][pixel[1]]++;
- cur_bins[2][pixel[2]]++;
- }
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
+ for (int j = 3; j--;) {
+ for (int i = 0; i < HIS_STEPS; i++) {
+ bins[j][i] += cur_bins[j][i];
}
}
+}
+
+static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int x;
+ unsigned int nr, ng, nb;
+
+ unsigned int bins[3][HIS_STEPS];
+
+ memset(bins, 0, sizeof(bins));
+
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -528,40 +547,38 @@ BLI_INLINE int get_bin_float(float f)
return (int) (((f + 0.25f) / 1.5f) * 512);
}
-static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+static void make_histogram_view_from_ibuf_float_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int nr, ng, nb, x, y;
+ const MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const float *src = ibuf->rect_float;
- unsigned int bins[3][HIS_STEPS];
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
- memset(bins, 0, sizeof(bins));
+ for (int x = 0; x < ibuf->x; x++) {
+ const float *pixel = src + (y * ibuf->x + x) * 4;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int j = 3; j--;) {
+ cur_bins[j][get_bin_float(pixel[j])]++;
+ }
+ }
+}
- memset(cur_bins, 0, sizeof(cur_bins));
+static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int nr, ng, nb;
+ int x;
- for (x = 0; x < ibuf->x; x++) {
- const float *pixel = src + (y * ibuf->x + x) * 4;
+ unsigned int bins[3][HIS_STEPS];
- cur_bins[0][get_bin_float(pixel[0])]++;
- cur_bins[1][get_bin_float(pixel[1])]++;
- cur_bins[2][get_bin_float(pixel[2])]++;
- }
+ memset(bins, 0, sizeof(bins));
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
- }
- }
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 9917486d549..f4171221816 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"
@@ -1090,20 +1091,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);
@@ -1174,7 +1256,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);
@@ -1187,7 +1269,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);
}
@@ -1197,7 +1279,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);
}
}
@@ -1887,7 +1969,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 53d4ac088e5..1c1068eff78 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -711,6 +711,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))
@@ -997,7 +999,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);
@@ -1181,7 +1192,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
set_face_cb = NULL;
/* test if we can use glsl */
- bool glsl = (v3d->drawtype == OB_MATERIAL) && !picking;
+ const int drawtype = view3d_effective_drawtype(v3d);
+ bool glsl = (drawtype == OB_MATERIAL) && !picking;
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index cdee56dd6d8..109a4952e52 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -225,16 +225,25 @@ static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], con
glColor3fv(col);
}
+int view3d_effective_drawtype(const struct View3D *v3d)
+{
+ if (v3d->drawtype == OB_RENDER) {
+ return v3d->prev_drawtype;
+ }
+ return v3d->drawtype;
+}
+
/* this condition has been made more complex since editmode can draw textures */
bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
{
+ const int v3d_drawtype = view3d_effective_drawtype(v3d);
/* texture and material draw modes */
- if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
+ if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
return true;
}
/* textured solid */
- if ((v3d->drawtype == OB_SOLID) &&
+ if ((v3d_drawtype == OB_SOLID) &&
(v3d->flag2 & V3D_SOLID_TEX) &&
(BKE_scene_use_new_shading_nodes(scene) == false))
{
@@ -296,7 +305,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
return true;
-
+
if (v3d->drawtype == OB_TEXTURE)
return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
@@ -1656,7 +1665,8 @@ static void draw_viewport_object_reconstruction(
v3d->bundle_size / 0.05f / camera_size[1],
v3d->bundle_size / 0.05f / camera_size[2]);
- if (v3d->drawtype == OB_WIRE) {
+ const int v3d_drawtype = view3d_effective_drawtype(v3d);
+ if (v3d_drawtype == OB_WIRE) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
glColor3ubv(ob_wire_col);
@@ -1668,7 +1678,7 @@ static void draw_viewport_object_reconstruction(
drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
}
- else if (v3d->drawtype > OB_WIRE) {
+ else if (v3d_drawtype > OB_WIRE) {
if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
/* selection outline */
if (selected) {
@@ -6436,7 +6446,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* maximum drawtype */
char dt = v3d->drawtype;
- if (dt == OB_RENDER) dt = OB_SOLID;
+ if (dt == OB_RENDER) dt = v3d->prev_drawtype;
dt = MIN2(dt, ob->dt);
if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE;
short dtx = 0;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 027d90ef039..d060a4a4b4c 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);
@@ -2602,19 +2602,20 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
{
CustomDataMask mask = 0;
+ const int drawtype = view3d_effective_drawtype(v3d);
- if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) ||
- ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
+ if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
+ ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
{
mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
if (BKE_scene_use_new_shading_nodes(scene)) {
- if (v3d->drawtype == OB_MATERIAL)
+ if (drawtype == OB_MATERIAL)
mask |= CD_MASK_ORCO;
}
else {
- if ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL))
+ if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) ||
+ (drawtype == OB_MATERIAL))
{
mask |= CD_MASK_ORCO;
}
@@ -3961,6 +3962,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 f636a07b064..48701ed1db6 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"
@@ -73,6 +74,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"
@@ -1228,6 +1230,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,
@@ -1646,8 +1650,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;
@@ -1714,6 +1720,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;
@@ -2023,6 +2032,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);
@@ -2502,6 +2513,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);
@@ -2742,6 +2755,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) {
@@ -2837,6 +2852,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;
@@ -3003,6 +3020,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];
@@ -3015,6 +3034,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... */
@@ -3031,7 +3054,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)) {
@@ -3192,6 +3227,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));
@@ -3231,6 +3268,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)) {
@@ -3836,6 +3875,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");
@@ -3986,6 +4027,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);
@@ -4191,6 +4234,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];
@@ -4243,6 +4289,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);
@@ -4796,6 +4844,35 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/* ************************* Toggle rendered shading *********************** */
+
+static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->drawtype == OB_RENDER) {
+ v3d->drawtype = v3d->prev_drawtype;
+ }
+ else {
+ v3d->prev_drawtype = v3d->drawtype;
+ v3d->drawtype = OB_RENDER;
+ }
+ ED_view3d_shade_update(CTX_data_main(C), CTX_data_scene(C), v3d, CTX_wm_area(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_render(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Rendered Shading";
+ ot->description = "Toggle rendered shading mode of the viewport";
+ ot->idname = "VIEW3D_OT_toggle_render";
+
+ /* api callbacks */
+ ot->exec = toggle_render_exec;
+ ot->poll = ED_operator_view3d_active;
+}
+
/* ************************* below the line! *********************** */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 4da3ba352b6..2d050c4fa95 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -103,6 +103,7 @@ void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot);
void VIEW3D_OT_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_render(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
@@ -158,6 +159,8 @@ enum {
V3D_CACHE_TEXT_LOCALCLIP = (1 << 4)
};
+int view3d_effective_drawtype(const struct View3D *v3d);
+
/* drawarmature.c */
bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
const short dt, const short dflag, const unsigned char ob_wire_col[4],
@@ -229,6 +232,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 c30e688f1e7..1c84ce3c985 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -218,7 +218,9 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
-
+
+ WM_operatortype_append(VIEW3D_OT_toggle_render);
+
transform_operatortypes();
}
@@ -417,10 +419,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_string_set(kmi->ptr, "value_1", "SOLID");
RNA_string_set(kmi->ptr, "value_2", "TEXTURED");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade");
- RNA_string_set(kmi->ptr, "value_1", "SOLID");
- RNA_string_set(kmi->ptr, "value_2", "RENDERED");
+ WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0);
/* selection*/
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index cbabc8e56de..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);
}
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 26eb707624a..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"
@@ -47,6 +49,7 @@
#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"
@@ -719,13 +722,13 @@ static bool view3d_ruler_item_mousemove(
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);
}
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 73ec0f664da..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 */
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 9c718285ada..b6c026ebd37 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 3c69a1cd6c3..f4d93389776 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 {
@@ -105,7 +106,7 @@ typedef struct TransSnap {
/**
* Re-usable snap context data.
*/
- SnapObjectContext *object_context;
+ struct SnapObjectContext *object_context;
} TransSnap;
typedef struct TransCon {
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 2139dba8a79..137f7c1656a 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -818,6 +818,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 */
@@ -832,6 +833,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);
@@ -847,10 +849,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);
}
}
@@ -7622,7 +7624,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 537e6e65dce..28202f21c0e 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -960,6 +960,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)
{
@@ -974,7 +984,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);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 236a223b5ff..1bb8b768981 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -68,6 +68,7 @@
#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"
@@ -485,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;
@@ -558,11 +588,18 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
- if (t->flag & (T_OBJECT | T_EDIT)) {
- if (t->spacetype == SPACE_VIEW3D) {
+ 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);
+ 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)));
}
}
}
@@ -918,86 +955,10 @@ 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 */
@@ -1242,8 +1203,6 @@ bool snapObjectsTransform(
float *dist_px,
float r_loc[3], float r_no[3])
{
- float ray_dist = BVH_RAYCAST_DIST_MAX;
-
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
&(const struct SnapObjectParams){
@@ -1252,269 +1211,94 @@ bool snapObjectsTransform(
.use_object_edit = (t->flag & T_EDIT) != 0,
.use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0,
},
- mval, dist_px,
- &ray_dist,
+ mval, dist_px, NULL,
r_loc, r_no, NULL);
}
/******************** PEELING *********************************/
-
-static int cmpPeel(const void *arg1, const void *arg2)
+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)
{
- 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;
+ 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;
}
-
- 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);
+ struct SnapObjectHitDepth *hit_max = NULL;
+
+ 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;
+ }
}
}
-
- 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);
+ else {
+ /* 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 if (iter->depth < hit_max->depth) {
+ hit_max = iter;
+ }
+ }
+ }
+ /* in this case has only one hit. treat as raycast */
+ if (hit_max == NULL) {
+ hit_max = hit_min;
}
-
- 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;
+ mid_v3_v3v3(r_loc, hit_min->co, hit_max->co);
- 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);
- }
+ if (r_thickness) {
+ *r_thickness = hit_max->depth - hit_min->depth;
+ }
- retval = retval || val;
-
- dm->release(dm);
- }
- }
-
- free_object_duplilist(lb);
- }
-
- if (ob->type == OB_MESH) {
- bool val = false;
+ /* 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 (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_freelistN(&depths_peel);
+ return true;
}
-
- 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
index e9209eea0e7..bf4a3116eeb 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -33,6 +33,8 @@
#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"
@@ -51,15 +53,30 @@
#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 {
- BVHTreeFromMesh *bvh_trees[2];
+ 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;
@@ -81,8 +98,124 @@ struct SnapObjectContext {
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
@@ -179,7 +312,7 @@ static bool snapEdge(
}
static bool snapVertex(
- ARegion *ar, const float vco[3], const short vno[3],
+ 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])
@@ -216,7 +349,7 @@ static bool snapVertex(
copy_v3_v3(r_loc, location);
if (r_no) {
- normal_short_to_float_v3(r_no, vno);
+ copy_v3_v3(r_no, vno);
mul_m3_v3(timat, r_no);
normalize_v3(r_no);
}
@@ -543,16 +676,33 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
static bool snapDerivedMesh(
SnapObjectContext *sctx,
- Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
+ 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,
- float r_loc[3], float r_no[3], int *r_index)
+ 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;
- int totvert = dm->getNumVerts(dm);
- if (totvert > 0) {
+ 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));
@@ -579,19 +729,6 @@ static bool snapDerivedMesh(
local_depth *= local_scale;
}
- SnapObjectData *sod = NULL;
-
- 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_alloc(sctx->cache.mem_arena, sizeof(*sod));
- memset(sod, 0, sizeof(*sod));
- }
- }
-
if (do_bb) {
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -619,9 +756,19 @@ static bool snapDerivedMesh(
}
}
+ 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:
@@ -633,9 +780,16 @@ static bool snapDerivedMesh(
}
if (tree_index != -1) {
if (sod->bvh_trees[tree_index] == NULL) {
- sod->bvh_trees[tree_index] = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*treedata));
+ 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 {
@@ -645,9 +799,7 @@ static bool snapDerivedMesh(
}
}
- if (treedata) {
- treedata->em_evil = em;
- treedata->em_evil_all = false;
+ if (treedata && treedata->tree == NULL) {
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
@@ -699,31 +851,55 @@ static bool snapDerivedMesh(
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]);
+ 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]);
+ }
}
}
}
@@ -741,8 +917,10 @@ static bool snapDerivedMesh(
&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, v->no, obmat, timat, mval, dist_px,
+ ar, v->co, vno, obmat, timat, mval, dist_px,
ray_start, ray_start_local, ray_normal_local, ray_depth,
r_loc, r_no);
}
@@ -753,45 +931,288 @@ static bool snapDerivedMesh(
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 (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);
}
- for (i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- bool test = true;
+ break;
+ }
+ }
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- }
- else {
- index = i;
- }
+ if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
+ if (treedata) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ }
+ }
- if (index == ORIGINDEX_NONE) {
- test = false;
- }
- else {
- BMEdge *eed = BM_edge_at_index(em->bm, index);
+ return retval;
+}
- 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;
+
+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;
- if (test) {
+ 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, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
+ 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);
@@ -804,7 +1225,7 @@ static bool snapDerivedMesh(
if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
if (treedata) {
- free_bvhtree_from_mesh(treedata);
+ free_bvhtree_from_editmesh(treedata);
}
}
}
@@ -815,28 +1236,33 @@ static bool snapDerivedMesh(
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 float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ 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])
+ 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;
- DerivedMesh *dm;
- bool do_bb = true;
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
- dm = editbmesh_get_derived_cage(sctx->scene, ob, em, CD_MASK_BAREMESH);
- do_bb = false;
+ 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);
@@ -844,15 +1270,14 @@ static bool snapObject(
else {
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
- em = NULL;
- }
+ 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);
- retval = snapDerivedMesh(
- sctx, ob, dm, em, obmat, mval, dist_px, snap_to, do_bb,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index);
-
- dm->release(dm);
+ dm->release(dm);
+ }
}
else if (ob->type == OB_ARMATURE) {
retval = snapArmature(
@@ -898,19 +1323,22 @@ static bool snapObjectsRay(
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])
+ 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_select == SNAP_ALL && obedit) {
+ if (snap_obedit_first) {
Object *ob = obedit;
retval |= snapObject(
sctx, ob, ob->obmat, true, snap_to,
- mval, dist_px,
+ mval, dist_px, ob_index++,
ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat);
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
for (base = sctx->scene->base.first; base != NULL; base = base->next) {
@@ -924,12 +1352,6 @@ static bool snapObjectsRay(
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(sctx->bmain->eval_ctx, sctx->scene, ob);
@@ -940,19 +1362,33 @@ static bool snapObjectsRay(
retval |= snapObject(
sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
- mval, dist_px,
+ mval, dist_px, ob_index++,
ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat);
+ 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,
+ mval, dist_px, ob_index++,
ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat);
+ r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -999,12 +1435,28 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(
return sctx;
}
-static void snap_object_data_free(void *val)
+static void snap_object_data_free(void *sod_v)
{
- SnapObjectData *sod = val;
- for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
- if (sod->bvh_trees[i]) {
- free_bvhtree_from_mesh(sod->bvh_trees[i]);
+ 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;
}
}
}
@@ -1019,6 +1471,19 @@ void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
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,
@@ -1037,7 +1502,53 @@ bool ED_transform_snap_object_project_ray_ex(
base_act, obedit,
ray_start, ray_normal, ray_start, ray_depth,
r_loc, r_no, r_index,
- r_ob, r_obmat);
+ 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;
}
/**
@@ -1049,7 +1560,7 @@ bool ED_transform_snap_object_project_ray_ex(
*/
static bool transform_snap_context_project_ray_impl(
SnapObjectContext *sctx,
- const float ray_start[3], const float ray_normal[3], float *ray_dist,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_co[3], float r_no[3])
{
bool ret;
@@ -1062,7 +1573,7 @@ static bool transform_snap_context_project_ray_impl(
.snap_to = SCE_SNAP_MODE_FACE,
.use_object_edit = (sctx->scene->obedit != NULL),
},
- ray_start, ray_normal, ray_dist,
+ ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
NULL, NULL);
@@ -1071,13 +1582,13 @@ static bool transform_snap_context_project_ray_impl(
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
- const float ray_origin[3], const float ray_direction[3], float *ray_dist,
+ const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3])
{
- float ray_dist_fallback;
- if (ray_dist == NULL) {
- ray_dist_fallback = BVH_RAYCAST_DIST_MAX;
- ray_dist = &ray_dist_fallback;
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
}
float no_fallback[3];
@@ -1087,7 +1598,7 @@ bool ED_transform_snap_object_project_ray(
return transform_snap_context_project_ray_impl(
sctx,
- ray_origin, ray_direction, ray_dist,
+ ray_origin, ray_direction, ray_depth,
r_co, r_no);
}
@@ -1098,7 +1609,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
bool use_depth,
float r_co[3], float r_no[3])
{
- float ray_dist = BVH_RAYCAST_DIST_MAX;
+ float ray_depth = BVH_RAYCAST_DIST_MAX;
bool is_hit = false;
float r_no_dummy[3];
@@ -1116,7 +1627,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
for (int i = 0; i < 3; i++) {
if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
if (use_depth == false) {
- ray_dist = BVH_RAYCAST_DIST_MAX;
+ ray_depth = BVH_RAYCAST_DIST_MAX;
}
params_temp.snap_to = elem_type[i];
@@ -1124,7 +1635,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
if (ED_transform_snap_object_project_view3d(
sctx,
&params_temp,
- mval, dist_px, &ray_dist,
+ mval, dist_px, &ray_depth,
r_co, r_no))
{
is_hit = true;
@@ -1171,6 +1682,12 @@ bool ED_transform_snap_object_project_view3d_ex(
{
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))
@@ -1186,7 +1703,7 @@ bool ED_transform_snap_object_project_view3d_ex(
mval, dist_px,
base_act, obedit,
ray_start, ray_normal, ray_orgigin, ray_depth,
- r_loc, r_no, r_index, NULL, NULL);
+ r_loc, r_no, r_index, NULL, NULL, NULL);
}
bool ED_transform_snap_object_project_view3d(
@@ -1204,4 +1721,32 @@ bool ED_transform_snap_object_project_view3d(
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 e105b6f893d..321b1043595 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -82,6 +82,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/undo.c b/source/blender/editors/util/undo.c
index 2a58b1fd2ec..805238bd2af 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -420,7 +420,8 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev
enum {
UNDOSYSTEM_GLOBAL = 1,
UNDOSYSTEM_EDITMODE = 2,
- UNDOSYSTEM_IMAPAINT = 3
+ UNDOSYSTEM_IMAPAINT = 3,
+ UNDOSYSTEM_SCULPT = 4,
};
static int get_undo_system(bContext *C)
@@ -450,6 +451,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;
@@ -474,6 +479,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);
}
@@ -552,6 +560,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/GPU_material.h b/source/blender/gpu/GPU_material.h
index c0b75748e1f..f77b62260be 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -277,6 +277,7 @@ typedef struct GPUInputUniform {
GPUDataType datatype; /* type of uniform data */
struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
+ struct Material *material;/* when type=GPU_DYNAMIC_MAT_... */
int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
int texsize; /* size in pixel of the texture in texpixels buffer:
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index f2871dcc9d6..aada3800ede 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -559,7 +559,8 @@ void GPU_basic_shader_light_set(int light_num, GPULightData *light)
GPU_MATERIAL_STATE.lights_directional |= light_bit;
}
else {
- if (USE_GLSL) {
+ /* TODO(sergey): Needs revisit. */
+ if (USE_GLSL || true) {
/* glsl shader needs these zero to skip them */
const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 9c14cc704e1..6ff4a60610b 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -823,7 +823,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
for (i = 0; i < numdata; i++) {
glEnableVertexAttribArray(data[i].index);
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
- GL_FALSE, elementsize, BUFFER_OFFSET(offset));
+ GL_TRUE, elementsize, BUFFER_OFFSET(offset));
offset += data[i].size * GPU_typesize(data[i].type);
attribData[i].index = data[i].index;
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index f63d5cf860f..a0fd9417af0 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -508,6 +508,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;
@@ -574,17 +626,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 */
@@ -621,12 +674,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 {
@@ -649,13 +697,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_material.c b/source/blender/gpu/intern/gpu_material.c
index f203ff1be4f..2bded95a1b5 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1590,22 +1590,22 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
shi->gpumat = mat;
shi->mat = ma;
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, NULL), &shi->mir);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir);
GPU_link(mat, "set_rgba_zero", &shi->refcol);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, NULL), &shi->alpha);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha);
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit);
- GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
@@ -2685,6 +2685,9 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
uniform->lamp = input->dynamicdata;
+
+ if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_MAT)
+ uniform->material = input->dynamicdata;
}
if (uniform->type != GPU_DYNAMIC_NONE)
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 49f244083f9..25352001056 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -205,6 +205,10 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
if (GPU_bicubic_bump_support())
strcat(defines, "#define BUMP_BICUBIC\n");
+ if (GLEW_VERSION_3_0) {
+ strcat(defines, "#define BIT_OPERATIONS\n");
+ }
+
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Check whether we actually compiling shader for
* the OpenSubdiv mesh.
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index e30b68bbab5..2f501dfab05 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -58,83 +58,83 @@ void main()
{
#if defined(USE_STIPPLE)
#if defined(DRAW_LINE)
- /* GLSL 1.3 */
- if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
- discard;
+ /* GLSL 1.3 */
+ if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
+ discard;
#else
- /* We have to use mod function and integer casting.
- * This can be optimized further with the bitwise operations
- * when GLSL 1.3 is supported. */
- if (stipple_id == STIPPLE_HALFTONE ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- {
- int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_QUARTTONE) {
- int mody = int(mod(gl_FragCoord.y, 4));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody == 0) {
- if (modx != 2)
- discard;
- }
- else if (mody == 2){
- if (modx != 0)
- discard;
- }
- else
- discard;
- }
- else if (stipple_id == STIPPLE_CHECKER_8PX) {
- int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y)/8, 2));
- if (result != 0)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
- int result = int(mod(gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
- int result = int(mod(gl_FragCoord.x, 2));
- bool dis = result != 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_HEXAGON) {
- int mody = int(mod(gl_FragCoord.y, 2));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody != 0) {
- if (modx != 1)
- discard;
- }
- else {
- if (modx != 3)
- discard;
- }
- }
+ /* We have to use mod function and integer casting.
+ * This can be optimized further with the bitwise operations
+ * when GLSL 1.3 is supported. */
+ if (stipple_id == STIPPLE_HALFTONE ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ {
+ int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_QUARTTONE) {
+ int mody = int(mod(gl_FragCoord.y, 4));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody == 0) {
+ if (modx != 2)
+ discard;
+ }
+ else if (mody == 2) {
+ if (modx != 0)
+ discard;
+ }
+ else
+ discard;
+ }
+ else if (stipple_id == STIPPLE_CHECKER_8PX) {
+ int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y) / 8, 2));
+ if (result != 0)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
+ int result = int(mod(gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
+ int result = int(mod(gl_FragCoord.x, 2));
+ bool dis = result != 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_HEXAGON) {
+ int mody = int(mod(gl_FragCoord.y, 2));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody != 0) {
+ if (modx != 1)
+ discard;
+ }
+ else {
+ if (modx != 3)
+ discard;
+ }
+ }
#endif /* !DRAW_LINE */
#endif /* USE_STIPPLE */
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
index ffd747ab1eb..674dd534352 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -52,13 +52,13 @@ void main(void)
*/
float t0 = start.z + start.w;
float t1 = end.z + end.w;
- if(t0 < 0.0) {
- if(t1 < 0.0) {
+ if (t0 < 0.0) {
+ if (t1 < 0.0) {
return;
}
start = mix(start, end, (0 - t0) / (t1 - t0));
}
- if(t1 < 0.0) {
+ if (t1 < 0.0) {
end = mix(start, end, (0 - t0) / (t1 - t0));
}
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index e6af492998d..9e22863a895 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -49,7 +49,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
index e315d2fb97a..7657fbb71ab 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -102,7 +102,8 @@ void accumulate_pass(void) {
if (dof_params.w == 0.0)
r = 1.0;
else
- r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+ r = cos(M_PI / dof_params.w) /
+ (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
if (dot(particlecoord, particlecoord) > r * r)
discard;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 494a74dcdf8..c2cd927898e 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -44,7 +44,8 @@ float calculate_ssao_factor(float depth)
vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth);
vec3 normal = calculate_view_space_normal(position);
- // find the offset in screen space by multiplying a point in camera space at the depth of the point by the projection matrix.
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
vec2 offset;
float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3];
offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 72a59e6843d..a63e7b8dbf0 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -16,17 +16,17 @@ float exp_blender(float f)
float compatible_pow(float x, float y)
{
- if(y == 0.0) /* x^0 -> 1, including 0^0 */
+ if (y == 0.0) /* x^0 -> 1, including 0^0 */
return 1.0;
/* glsl pow doesn't accept negative x */
- if(x < 0.0) {
- if(mod(-y, 2.0) == 0.0)
+ if (x < 0.0) {
+ if (mod(-y, 2.0) == 0.0)
return pow(-x, y);
else
return -pow(-x, y);
}
- else if(x == 0.0)
+ else if (x == 0.0)
return 0.0;
return pow(x, y);
@@ -77,11 +77,11 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
s = hsv[1];
v = hsv[2];
- if(s==0.0) {
+ if (s==0.0) {
rgb = vec3(v, v, v);
}
else {
- if(h==1.0)
+ if (h==1.0)
h = 0.0;
h *= 6.0;
@@ -105,7 +105,7 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
float srgb_to_linearrgb(float c)
{
- if(c < 0.04045)
+ if (c < 0.04045)
return (c < 0.0) ? 0.0: c * (1.0 / 12.92);
else
return pow((c + 0.055)*(1.0/1.055), 2.4);
@@ -113,7 +113,7 @@ float srgb_to_linearrgb(float c)
float linearrgb_to_srgb(float c)
{
- if(c < 0.0031308)
+ if (c < 0.0031308)
return (c < 0.0) ? 0.0: c * 12.92;
else
return 1.055 * pow(c, 1.0/2.4) - 0.055;
@@ -142,6 +142,20 @@ void color_to_normal(vec3 color, out vec3 normal)
normal.z = 2.0 * ((color.b) - 0.5);
}
+void color_to_normal_new_shading(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);
+}
+
+void color_to_blender_normal_new_shading(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
@@ -149,7 +163,7 @@ void color_to_normal(vec3 color, out vec3 normal)
void vcol_attribute(vec4 attvcol, out vec4 vcol)
{
- vcol = vec4(attvcol.x/255.0, attvcol.y/255.0, attvcol.z/255.0, 1.0);
+ vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
}
void uv_attribute(vec2 attuv, out vec3 uv)
@@ -157,7 +171,10 @@ void uv_attribute(vec2 attuv, out vec3 uv)
uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0);
}
-void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol, out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv, out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
+void geom(
+ vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol,
+ out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv,
+ out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
{
local = co;
view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(local): vec3(0.0, 0.0, -1.0);
@@ -171,16 +188,19 @@ void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 att
frontback = (gl_FrontFacing)? 1.0: 0.0;
}
-void particle_info(vec4 sprops, vec3 loc, vec3 vel, vec3 avel, out float index, out float age, out float life_time, out vec3 location, out float size, out vec3 velocity, out vec3 angular_velocity)
+void particle_info(
+ vec4 sprops, vec3 loc, vec3 vel, vec3 avel,
+ out float index, out float age, out float life_time, out vec3 location,
+ out float size, out vec3 velocity, out vec3 angular_velocity)
{
- index = sprops.x;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
+ index = sprops.x;
+ age = sprops.y;
+ life_time = sprops.z;
+ size = sprops.w;
- location = loc;
- velocity = vel;
- angular_velocity = avel;
+ location = loc;
+ velocity = vel;
+ angular_velocity = avel;
}
void vect_normalize(vec3 vin, out vec3 vout)
@@ -201,9 +221,9 @@ void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
{
outvec = (mat * vec4(vec, 1.0)).xyz;
- if(domin == 1.0)
+ if (domin == 1.0)
outvec = max(outvec, minvec);
- if(domax == 1.0)
+ if (domax == 1.0)
outvec = min(outvec, maxvec);
}
@@ -214,7 +234,9 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void lamp(vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
+void lamp(
+ vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac,
+ out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
{
outcol = col * energy;
outlv = lv;
@@ -299,7 +321,7 @@ void math_pow(float val1, float val2, out float outval)
void math_log(float val1, float val2, out float outval)
{
- if(val1 > 0.0 && val2 > 0.0)
+ if (val1 > 0.0 && val2 > 0.0)
outval= log2(val1) / log2(val2);
else
outval= 0.0;
@@ -322,7 +344,7 @@ void math_round(float val, out float outval)
void math_less_than(float val1, float val2, out float outval)
{
- if(val1 < val2)
+ if (val1 < val2)
outval = 1.0;
else
outval = 0.0;
@@ -330,7 +352,7 @@ void math_less_than(float val1, float val2, out float outval)
void math_greater_than(float val1, float val2, out float outval)
{
- if(val1 > val2)
+ if (val1 > val2)
outval = 1.0;
else
outval = 0.0;
@@ -350,7 +372,7 @@ void math_modulo(float val1, float val2, out float outval)
void math_abs(float val1, out float outval)
{
- outval = abs(val1);
+ outval = abs(val1);
}
void squeeze(float val, float width, float center, out float outval)
@@ -407,8 +429,8 @@ void vec_math_negate(vec3 v, out vec3 outv)
void invert_z(vec3 v, out vec3 outv)
{
- v.z = -v.z;
- outv = v;
+ v.z = -v.z;
+ outv = v;
}
void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
@@ -539,17 +561,17 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(outcol.r < 0.5)
+ if (outcol.r < 0.5)
outcol.r *= facm + 2.0*fac*col2.r;
else
outcol.r = 1.0 - (facm + 2.0*fac*(1.0 - col2.r))*(1.0 - outcol.r);
- if(outcol.g < 0.5)
+ if (outcol.g < 0.5)
outcol.g *= facm + 2.0*fac*col2.g;
else
outcol.g = 1.0 - (facm + 2.0*fac*(1.0 - col2.g))*(1.0 - outcol.g);
- if(outcol.b < 0.5)
+ if (outcol.b < 0.5)
outcol.b *= facm + 2.0*fac*col2.b;
else
outcol.b = 1.0 - (facm + 2.0*fac*(1.0 - col2.b))*(1.0 - outcol.b);
@@ -569,9 +591,9 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r;
- if(col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g;
- if(col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b;
+ if (col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r;
+ if (col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g;
+ if (col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b;
}
void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -600,29 +622,29 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
outcol = col1;
- if(outcol.r != 0.0) {
+ if (outcol.r != 0.0) {
float tmp = 1.0 - fac*col2.r;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.r = 1.0;
- else if((tmp = outcol.r/tmp) > 1.0)
+ else if ((tmp = outcol.r/tmp) > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
}
- if(outcol.g != 0.0) {
+ if (outcol.g != 0.0) {
float tmp = 1.0 - fac*col2.g;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.g = 1.0;
- else if((tmp = outcol.g/tmp) > 1.0)
+ else if ((tmp = outcol.g/tmp) > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
}
- if(outcol.b != 0.0) {
+ if (outcol.b != 0.0) {
float tmp = 1.0 - fac*col2.b;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.b = 1.0;
- else if((tmp = outcol.b/tmp) > 1.0)
+ else if ((tmp = outcol.b/tmp) > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -637,31 +659,31 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
tmp = facm + fac*col2.r;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.r = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0)
outcol.r = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
tmp = facm + fac*col2.g;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.g = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0)
outcol.g = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
tmp = facm + fac*col2.b;
- if(tmp <= 0.0)
+ if (tmp <= 0.0)
outcol.b = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0)
outcol.b = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -677,7 +699,7 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv_to_rgb(hsv, tmp);
@@ -697,7 +719,7 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2;
rgb_to_hsv(outcol, hsv);
- if(hsv.y != 0.0) {
+ if (hsv.y != 0.0) {
rgb_to_hsv(col2, hsv2);
hsv.y = facm*hsv.y + fac*hsv2.y;
@@ -728,7 +750,7 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv.y = hsv2.y;
@@ -794,11 +816,11 @@ void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 ou
rgb_to_hsv(col, hsv);
hsv[0] += (hue - 0.5);
- if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ if (hsv[0]>1.0) hsv[0]-=1.0; else if (hsv[0]<0.0) hsv[0]+= 1.0;
hsv[1] *= sat;
- if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
+ if (hsv[1]>1.0) hsv[1]= 1.0; else if (hsv[1]<0.0) hsv[1]= 0.0;
hsv[2] *= value;
- if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0;
+ if (hsv[2]>1.0) hsv[2]= 1.0; else if (hsv[2]<0.0) hsv[2]= 0.0;
hsv_to_rgb(hsv, outcol);
@@ -936,7 +958,7 @@ void shade_norm(vec3 normal, out vec3 outnormal)
void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol)
{
- outrefcol = mix(refcol, vec4(1.0, tcol), tin*colmirfac);
+ outrefcol = mix(refcol, vec4(1.0, tcol), tin * colmirfac);
}
void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -976,17 +998,17 @@ void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
fact *= facg;
facm = 1.0-fact;
- if(outcol.r < 0.5)
+ if (outcol.r < 0.5)
incol.r = outcol.r*(facm + 2.0*fact*texcol.r);
else
incol.r = 1.0 - (facm + 2.0*fact*(1.0 - texcol.r))*(1.0 - outcol.r);
- if(outcol.g < 0.5)
+ if (outcol.g < 0.5)
incol.g = outcol.g*(facm + 2.0*fact*texcol.g);
else
incol.g = 1.0 - (facm + 2.0*fact*(1.0 - texcol.g))*(1.0 - outcol.g);
- if(outcol.b < 0.5)
+ if (outcol.b < 0.5)
incol.b = outcol.b*(facm + 2.0*fact*texcol.b);
else
incol.b = 1.0 - (facm + 2.0*fact*(1.0 - texcol.b))*(1.0 - outcol.b);
@@ -1009,9 +1031,9 @@ void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
fact *= facg;
facm = 1.0-fact;
- if(texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r;
- if(texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g;
- if(texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b;
+ if (texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r;
+ if (texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g;
+ if (texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b;
}
void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1043,11 +1065,11 @@ void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
fact *= facg;
col = fact*texcol.r;
- if(col > outcol.r) incol.r = col; else incol.r = outcol.r;
+ if (col > outcol.r) incol.r = col; else incol.r = outcol.r;
col = fact*texcol.g;
- if(col > outcol.g) incol.g = col; else incol.g = outcol.g;
+ if (col > outcol.g) incol.g = col; else incol.g = outcol.g;
col = fact*texcol.b;
- if(col > outcol.b) incol.b = col; else incol.b = outcol.b;
+ if (col > outcol.b) incol.b = col; else incol.b = outcol.b;
}
void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1098,17 +1120,17 @@ void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
{
fact *= facg;
- if(texcol.r > 0.5)
+ if (texcol.r > 0.5)
incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5));
else
incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0);
- if(texcol.g > 0.5)
+ if (texcol.g > 0.5)
incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5));
else
incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0);
- if(texcol.b > 0.5)
+ if (texcol.b > 0.5)
incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5));
else
incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0);
@@ -1119,7 +1141,7 @@ void mtex_value_vars(inout float fact, float facg, out float facm)
fact *= abs(facg);
facm = 1.0-fact;
- if(facg < 0.0) {
+ if (facg < 0.0) {
float tmp = fact;
fact = facm;
facm = tmp;
@@ -1175,7 +1197,7 @@ void mtex_value_div(float outcol, float texcol, float fact, float facg, out floa
float facm;
mtex_value_vars(fact, facg, facm);
- if(texcol != 0.0)
+ if (texcol != 0.0)
incol = facm*outcol + fact*outcol/texcol;
else
incol = 0.0;
@@ -1203,7 +1225,7 @@ void mtex_value_light(float outcol, float texcol, float fact, float facg, out fl
mtex_value_vars(fact, facg, facm);
float col = fact*texcol;
- if(col > outcol) incol = col; else incol = outcol;
+ if (col > outcol) incol = col; else incol = outcol;
}
void mtex_value_clamp_positive(float fac, out float outfac)
@@ -1225,8 +1247,8 @@ void mtex_har_multiply_clamp(float har, out float outhar)
{
har *= 128.0;
- if(har < 1.0) outhar = 1.0;
- else if(har > 511.0) outhar = 511.0;
+ if (har < 1.0) outhar = 1.0;
+ else if (har > 511.0) outhar = 511.0;
else outhar = har;
}
@@ -1242,7 +1264,7 @@ void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol)
void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a * value);
+ outcol = vec4(col.rgb, col.a * value);
}
void mtex_rgbtoint(vec4 rgb, out float intensity)
@@ -1300,7 +1322,9 @@ void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
value = 1.0;
}
-void mtex_cube_map_refl(samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, out float value, out vec4 color)
+void mtex_cube_map_refl(
+ samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix,
+ out float value, out vec4 color)
{
vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
@@ -1343,11 +1367,12 @@ mat3 to_mat3(mat4 m4)
return m3;
}
-void mtex_bump_init_objspace( vec3 surf_pos, vec3 surf_norm,
- mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_objspace(
+ vec3 surf_pos, vec3 surf_norm,
+ mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
mat3 obj2view = to_mat3(gl_ModelViewMatrix);
mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
@@ -1370,10 +1395,11 @@ void mtex_bump_init_objspace( vec3 surf_pos, vec3 surf_norm,
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_texturespace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_texturespace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
vec3 vSigmaS = dFdx( surf_pos );
vec3 vSigmaT = dFdy( surf_pos );
@@ -1388,10 +1414,11 @@ void mtex_bump_init_texturespace( vec3 surf_pos, vec3 surf_norm,
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_viewspace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_viewspace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
vec3 vSigmaS = dFdx( surf_pos );
vec3 vSigmaT = dFdy( surf_pos );
@@ -1406,8 +1433,9 @@ void mtex_bump_init_viewspace( vec3 surf_pos, vec3 surf_norm,
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_tap3( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap3(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 STll = texco.xy;
vec2 STlr = texco.xy + dFdx(texco.xy) ;
@@ -1424,8 +1452,9 @@ void mtex_bump_tap3( vec3 texco, sampler2D ima, float hScale,
#ifdef BUMP_BICUBIC
-void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_bicubic(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt )
{
float Hl;
float Hr;
@@ -1447,7 +1476,7 @@ void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
float fBlend = clamp(1.0-textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
- if(fBlend!=0.0)
+ if (fBlend!=0.0)
{
// the derivative of the bicubic sampling of level 0
ivec2 vDim;
@@ -1478,8 +1507,8 @@ void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
mat4 H;
- for(int i = 0; i < 4; i++) {
- for(int j = 0; j < 4; j++) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
ivec2 iTexTmp = iTexLocMod + ivec2(i,j);
// wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range.
@@ -1516,8 +1545,9 @@ void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
#endif
-void mtex_bump_tap5( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap5(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
@@ -1539,8 +1569,9 @@ void mtex_bump_tap5( vec3 texco, sampler2D ima, float hScale,
dBt = hScale * (Hu - Hd);
}
-void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_deriv(
+ vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
+ out float dBs, out float dBt)
{
float s = 1.0; // negate this if flipped texture coordinate
vec2 TexDx = dFdx(texco.xy);
@@ -1555,8 +1586,9 @@ void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float
dBt = dBduv.x*TexDy.x + s*dBduv.y*TexDy.y;
}
-void mtex_bump_apply( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
vec3 vSurfGrad = sign(fDet) * ( dBs * vR1 + dBt * vR2 );
@@ -1564,9 +1596,10 @@ void mtex_bump_apply( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3
perturbed_norm = normalize( vNacc_out );
}
-void mtex_bump_apply_texspace( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
- sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply_texspace(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
+ sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
@@ -1574,7 +1607,7 @@ void mtex_bump_apply_texspace( float fDet, float dBs, float dBt, vec3 vR1, vec3
vec3 vSurfGrad = sign(fDet) * (
dBs / length( vec2(ima_x*TexDx.x, ima_y*TexDx.y) ) * vR1 +
dBt / length( vec2(ima_x*TexDy.x, ima_y*TexDy.y) ) * vR2 );
-
+
vNacc_out = vNacc_in - vSurfGrad;
perturbed_norm = normalize( vNacc_out );
}
@@ -1668,7 +1701,7 @@ void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
- if(dot(lv, lampvec) > 0.0) {
+ if (dot(lv, lampvec) > 0.0) {
vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
/* without clever non-uniform scale, we could do: */
// float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
@@ -1701,14 +1734,14 @@ void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac,
{
float t = spotsi;
- if(inpr <= t) {
+ if (inpr <= t) {
outvisifac = 0.0;
}
else {
t = inpr - t;
/* soft area */
- if(spotbl != 0.0)
+ if (spotbl != 0.0)
inpr *= smoothstep(0.0, 1.0, t/spotbl);
outvisifac = visifac*inpr;
@@ -1811,12 +1844,14 @@ float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
return max(fac, 0.0);
}
-void shade_inp_area(vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k, out float inp)
+void shade_inp_area(
+ vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k,
+ out float inp)
{
vec3 co = position;
vec3 vec = co - lampco;
- if(dot(vec, lampvec) < 0.0) {
+ if (dot(vec, lampvec) < 0.0) {
inp = 0.0;
}
else {
@@ -1833,10 +1868,10 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float nv = max(dot(n, v), 0.0);
float realnl = dot(n, l);
- if(realnl < 0.0) {
+ if (realnl < 0.0) {
is = 0.0;
}
- else if(nl < 0.0) {
+ else if (nl < 0.0) {
is = 0.0;
}
else {
@@ -1851,7 +1886,7 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float a, b;
- if(Lit_A > View_A) {
+ if (Lit_A > View_A) {
a = Lit_A;
b = View_A;
}
@@ -1873,20 +1908,20 @@ void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out f
float rslt = dot(n, l);
float ang = acos(rslt);
- if(ang < size) is = 1.0;
- else if(ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
+ if (ang < size) is = 1.0;
+ else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
else is = 1.0 - ((ang - size)/tsmooth);
}
void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is)
{
- if(nl <= 0.0) {
+ if (nl <= 0.0) {
is = 0.0;
}
else {
float nv = max(dot(n, v), 0.0);
- if(darkness <= 1.0)
+ if (darkness <= 1.0)
is = nl*pow(max(nv*nl, 0.1), darkness - 1.0);
else
is = nl*pow(1.0001 - nv, darkness - 1.0);
@@ -1898,18 +1933,18 @@ float fresnel_fac(vec3 view, vec3 vn, float grad, float fac)
float t1, t2;
float ffac;
- if(fac==0.0) {
+ if (fac==0.0) {
ffac = 1.0;
}
else {
t1= dot(view, vn);
- if(t1>0.0) t2= 1.0+t1;
+ if (t1>0.0) t2= 1.0+t1;
else t2= 1.0-t1;
t2= grad + (1.0-grad)*pow(t2, fac);
- if(t2<0.0) ffac = 0.0;
- else if(t2>1.0) ffac = 1.0;
+ if (t2<0.0) ffac = 0.0;
+ else if (t2>1.0) ffac = 1.0;
else ffac = t2;
}
@@ -1923,7 +1958,7 @@ void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac,
void shade_cubic(float is, out float outis)
{
- if(is>0.0 && is<1.0)
+ if (is>0.0 && is<1.0)
outis= smoothstep(0.0, 1.0, is);
else
outis= is;
@@ -1931,7 +1966,7 @@ void shade_cubic(float is, out float outis)
void shade_visifac(float i, float visifac, float refl, out float outi)
{
- /*if(i > 0.0)*/
+ /*if (i > 0.0)*/
outi = max(i*visifac*refl, 0.0);
/*else
outi = i;*/
@@ -1944,7 +1979,7 @@ void shade_tangent_v_spec(vec3 tang, out vec3 vn)
void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
{
- if(i > 0.0)
+ if (i > 0.0)
outcol = i*lampcol*col;
else
outcol = vec3(0.0, 0.0, 0.0);
@@ -1974,7 +2009,7 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
@@ -1988,27 +2023,27 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, out float specfac)
{
- if(refrac < 1.0) {
+ if (refrac < 1.0) {
specfac = 0.0;
}
- else if(spec_power == 0.0) {
+ else if (spec_power == 0.0) {
specfac = 0.0;
}
else {
- if(spec_power<100.0)
+ if (spec_power<100.0)
spec_power= sqrt(1.0/spec_power);
else
spec_power= 10.0/spec_power;
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
float nv = max(dot(n, v), 0.01);
float nl = dot(n, l);
- if(nl <= 0.01) {
+ if (nl <= 0.01) {
specfac = 0.0;
}
else {
@@ -2020,12 +2055,14 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou
float g = 0.0;
- if(a < b && a < c) g = a;
- else if(b < a && b < c) g = b;
- else if(c < a && c < b) g = c;
+ if (a < b && a < c) g = a;
+ else if (b < a && b < c) g = b;
+ else if (c < a && c < b) g = c;
- float p = sqrt(((refrac * refrac)+(vh*vh)-1.0));
- float f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1.0+((((vh*(p+vh))-1.0)*((vh*(p+vh))-1.0))/(((vh*(p-vh))+1.0)*((vh*(p-vh))+1.0))));
+ float p = sqrt(((refrac * refrac) + (vh * vh) - 1.0));
+ float f = ((((p - vh) * (p - vh)) / ((p + vh) * (p + vh))) *
+ (1.0 + ((((vh * (p + vh)) - 1.0) * ((vh * (p + vh)) - 1.0)) /
+ (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0)))));
float ang = acos(nh);
specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0);
@@ -2052,8 +2089,8 @@ void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out floa
float rslt = dot(h, n);
float ang = acos(rslt);
- if(ang < size) rslt = 1.0;
- else if(ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
+ if (ang < size) rslt = 1.0;
+ else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
else rslt = 1.0 - ((ang - size)/tsmooth);
specfac = rslt;
@@ -2076,7 +2113,7 @@ void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
{
- result = mir*refcol.gba + (vec3(1.0) - mir*refcol.rrr)*combined;
+ result = mir * refcol.gba + (vec3(1.0) - mir * refcol.rrr) * combined;
}
void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha)
@@ -2160,9 +2197,11 @@ void shade_clamp_positive(vec4 col, out vec4 outcol)
outcol = max(col, vec4(0.0));
}
-void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, out float result)
+void test_shadowbuf(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
@@ -2178,9 +2217,11 @@ void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, flo
}
}
-void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp, out float result)
+void test_shadowbuf_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
@@ -2190,7 +2231,7 @@ void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float
float dist = co.z/co.w;
float p = 0.0;
- if(dist <= moments.x)
+ if (dist <= moments.x)
p = 1.0;
float variance = moments.y - (moments.x*moments.x);
@@ -2210,11 +2251,14 @@ void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat,
+ float shadowbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac);
@@ -2222,11 +2266,14 @@ void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat,
+ float shadowbias, float bleedbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac);
@@ -2247,16 +2294,18 @@ void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outco
outcol = linfac*(1.0 - exp(col*logfac));
}
-void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac)
+void shade_mist_factor(
+ vec3 co, float enable, float miststa, float mistdist, float misttype, float misi,
+ out float outfac)
{
- if(enable == 1.0) {
+ if (enable == 1.0) {
float fac, zcor;
zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
- if(misttype == 0.0) fac *= fac;
- else if(misttype == 1.0);
+ if (misttype == 0.0) fac *= fac;
+ else if (misttype == 1.0);
else fac = sqrt(fac);
outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
@@ -2292,7 +2341,7 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float g = eta * eta - 1.0 + c * c;
float result;
- if(g > 0.0) {
+ if (g > 0.0) {
g = sqrt(g);
float A =(g - c)/(g + c);
float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0);
@@ -2310,6 +2359,89 @@ float hypot(float x, float y)
return sqrt(x*x + y*y);
}
+void generated_from_orco(vec3 orco, out vec3 generated)
+{
+ generated = orco * 0.5 + vec3(0.5);
+}
+
+float integer_noise(int n)
+{
+ int nn;
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5 * (float(nn) / 1073741824.0);
+}
+
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+#ifdef BIT_OPERATIONS
+uint hash(uint kx, uint ky, uint kz)
+{
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+ // now hash the data!
+ uint a, b, c, len = 3u;
+ a = b = c = 0xdeadbeefu + (len << 2u) + 13u;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+#undef rot
+#undef final
+}
+
+uint hash(int kx, int ky, int kz)
+{
+ return hash(uint(kx), uint(ky), uint(kz));
+}
+
+float bits_to_01(uint bits)
+{
+ float x = float(bits) * (1.0 / float(0xffffffffu));
+ return x;
+}
+
+float cellnoise(vec3 p)
+{
+ int ix = floor_to_int(p.x);
+ int iy = floor_to_int(p.y);
+ int iz = floor_to_int(p.z);
+
+ return bits_to_01(hash(uint(ix), uint(iy), uint(iz)));
+}
+
+vec3 cellnoise_color(vec3 p)
+{
+ float r = cellnoise(p);
+ float g = cellnoise(vec3(p.y, p.x, p.z));
+ float b = cellnoise(vec3(p.y, p.z, p.x));
+
+ return vec3(r, g, b);
+}
+#endif // BIT_OPERATIONS
+
+float floorfrac(float x, out int i)
+{
+ i = floor_to_int(x);
+ return x - i;
+}
+
/*********** NEW SHADER NODES ***************/
#define NUM_LIGHTS 3
@@ -2322,7 +2454,7 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
@@ -2339,7 +2471,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 H = gl_LightSource[i].halfVector.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
@@ -2354,7 +2486,9 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
result = vec4(L*color.rgb, 1.0);
}
-void node_bsdf_anisotropic(vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, out vec4 result)
+void node_bsdf_anisotropic(
+ vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2388,7 +2522,9 @@ void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, out vec4 result)
+void node_subsurface_scattering(
+ vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2466,7 +2602,7 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
/* facing */
facing = abs(dot(I_view, N));
- if(blend != 0.5) {
+ if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend);
facing = pow(facing, blend);
@@ -2480,21 +2616,24 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
outcol = col;
- if(col.r > 0.0)
+ if (col.r > 0.0)
outcol.r = compatible_pow(col.r, gamma);
- if(col.g > 0.0)
+ if (col.g > 0.0)
outcol.g = compatible_pow(col.g, gamma);
- if(col.b > 0.0)
+ if (col.b > 0.0)
outcol.b = compatible_pow(col.b, gamma);
}
/* geometry */
-void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float outf)
+void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
- outcol = vec4(attr_uv, 1.0);
- outvec = attr_uv;
- outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0;
+ /* TODO(sergey): This needs linearization for vertex color.
+ * But how to detect cases when input is linear and when it's srgb?
+ */
+ outcol = vec4(attr, 1.0);
+ outvec = attr;
+ outf = (attr.x + attr.y + attr.z)/3.0;
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2568,22 +2707,119 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, v
/* textures */
-void node_tex_gradient(vec3 co, out vec4 color, out float fac)
+float calc_gradient(vec3 p, int gradient_type)
{
- color = vec4(1.0);
- fac = 1.0;
+ float x, y, z;
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ if (gradient_type == 0) { /* linear */
+ return x;
+ }
+ else if (gradient_type == 1) { /* quadratic */
+ float r = max(x, 0.0);
+ return r*r;
+ }
+ else if (gradient_type == 2) { /* easing */
+ float r = min(max(x, 0.0), 1.0);
+ float t = r*r;
+ return (3.0*t - 2.0*t*r);
+ }
+ else if (gradient_type == 3) { /* diagonal */
+ return (x + y) * 0.5;
+ }
+ else if (gradient_type == 4) { /* radial */
+ return atan(y, x) / (M_PI * 2) + 0.5;
+ }
+ else {
+ float r = max(1.0 - sqrt(x*x + y*y + z*z), 0.0);
+ if (gradient_type == 5) { /* quadratic sphere */
+ return r*r;
+ }
+ else if (gradient_type == 6) { /* sphere */
+ return r;
+ }
+ }
+ return 0.0;
+}
+
+void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
+{
+ float f = calc_gradient(co, int(gradient_type));
+ f = clamp(f, 0.0, 1.0);
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
}
void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
{
- color = vec4(1.0);
- fac = 1.0;
+ vec3 p = co * scale;
+
+ /* Prevent precision issues on unit coordinates. */
+ p.x = (p.x + 0.000001)*0.999999;
+ p.y = (p.y + 0.000001)*0.999999;
+ p.z = (p.z + 0.000001)*0.999999;
+
+ int xi = abs(int(floor(p.x)));
+ int yi = abs(int(floor(p.y)));
+ int zi = abs(int(floor(p.z)));
+
+ bool check = ((xi % 2 == yi % 2) == bool(zi % 2));
+
+ color = check ? color1 : color2;
+ fac = check ? 1.0 : 0.0;
}
-void node_tex_brick(vec3 co, vec4 color1, vec4 color2, vec4 mortar, float scale, float mortar_size, float bias, float brick_width, float row_height, out vec4 color, out float fac)
+vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
+ float brick_width, float row_height,
+ float offset_amount, int offset_frequency,
+ float squash_amount, int squash_frequency)
{
- color = vec4(1.0);
- fac = 1.0;
+ int bricknum, rownum;
+ float offset = 0.0;
+ float x, y;
+
+ rownum = floor_to_int(p.y / row_height);
+
+ if (offset_frequency != 0 && squash_frequency != 0) {
+ brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width*offset_amount); /* offset */
+ }
+
+ bricknum = floor_to_int((p.x+offset) / brick_width);
+
+ x = (p.x+offset) - brick_width*bricknum;
+ y = p.y - row_height*rownum;
+
+ return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
+ (x < mortar_size || y < mortar_size ||
+ x > (brick_width - mortar_size) ||
+ y > (row_height - mortar_size)) ? 1.0 : 0.0);
+}
+
+void node_tex_brick(vec3 co,
+ vec4 color1, vec4 color2,
+ vec4 mortar, float scale,
+ float mortar_size, float bias,
+ float brick_width, float row_height,
+ float offset_amount, float offset_frequency,
+ float squash_amount, float squash_frequency,
+ out vec4 color, out float fac)
+{
+ vec2 f2 = calc_brick_texture(co*scale,
+ mortar_size, bias,
+ brick_width, row_height,
+ offset_amount, int(offset_frequency),
+ squash_amount, int(squash_frequency));
+ float tint = f2.x;
+ float f = f2.y;
+ if (f != 1.0) {
+ float facm = 1.0 - tint;
+ color1 = facm * color1 + tint * color2;
+ }
+ color = (f == 1.0) ? mortar : color1;
+ fac = f;
}
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -2608,7 +2844,7 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
nco.y -= 1.0;
float div = 2.0*sqrt(max(-0.5*nco.y, 0.0));
- if(div > 0.0)
+ if (div > 0.0)
nco /= div;
float u = 0.5*(nco.x + 1.0);
@@ -2634,22 +2870,398 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
alpha = 0.0;
}
-void node_tex_magic(vec3 p, float scale, float distortion, out vec4 color, out float fac)
+void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+ float x = sin((p.x + p.y + p.z)*5.0);
+ float y = cos((-p.x + p.y - p.z)*5.0);
+ float z = -cos((-p.x - p.y + p.z)*5.0);
+
+ if (depth > 0) {
+ x *= distortion;
+ y *= distortion;
+ z *= distortion;
+ y = -cos(x-y+z);
+ y *= distortion;
+ if (depth > 1) {
+ x = cos(x-y-z);
+ x *= distortion;
+ if (depth > 2) {
+ z = sin(-x-y-z);
+ z *= distortion;
+ if (depth > 3) {
+ x = -cos(-x+y-z);
+ x *= distortion;
+ if (depth > 4) {
+ y = -sin(-x+y+z);
+ y *= distortion;
+ if (depth > 5) {
+ y = -cos(-x+y+z);
+ y *= distortion;
+ if (depth > 6) {
+ x = cos(x+y+z);
+ x *= distortion;
+ if (depth > 7) {
+ z = sin(x+y-z);
+ z *= distortion;
+ if (depth > 8) {
+ x = -cos(-x-y+z);
+ x *= distortion;
+ if (depth > 9) {
+ y = -sin(x-y+z);
+ y *= distortion;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (distortion != 0.0) {
+ distortion *= 2.0;
+ x /= distortion;
+ y /= distortion;
+ z /= distortion;
+ }
+
+ color = vec4(0.5 - x, 0.5 - y, 0.f - z, 1.0);
+ fac = (color.x + color.y + color.z) / 3.0;
+}
+
+#ifdef BIT_OPERATIONS
+float noise_fade(float t)
{
- color = vec4(1.0);
- fac = 1.0;
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
-void node_tex_musgrave(vec3 co, float scale, float detail, float dimension, float lacunarity, float offset, float gain, out vec4 color, out float fac)
+float noise_scale3(float result)
{
- color = vec4(1.0);
- fac = 1.0;
+ return 0.9820 * result;
+}
+
+float noise_nerp(float t, float a, float b)
+{
+ return (1.0 - t) * a + t * b;
}
+float noise_grad(uint hash, float x, float y, float z)
+{
+ uint h = hash & 15u;
+ float u = h < 8u ? x : y;
+ float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float v = h < 4u ? y : vt;
+ return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v);
+}
+
+float noise_perlin(float x, float y, float z)
+{
+ int X; float fx = floorfrac(x, X);
+ int Y; float fy = floorfrac(y, Y);
+ int Z; float fz = floorfrac(z, Z);
+
+ float u = noise_fade(fx);
+ float v = noise_fade(fy);
+ float w = noise_fade(fz);
+
+ float result;
+
+ result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz ),
+ noise_grad(hash(X+1, Y, Z), fx-1.0, fy, fz)),
+ noise_nerp(u, noise_grad(hash(X, Y+1, Z), fx, fy - 1.0, fz),
+ noise_grad(hash(X+1, Y+1, Z), fx-1.0, fy-1.0, fz))),
+ noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z+1), fx, fy, fz-1.0),
+ noise_grad(hash(X+1, Y, Z+1), fx-1.0, fy, fz-1.0)),
+ noise_nerp(u, noise_grad(hash(X, Y+1, Z+1), fx, fy-1.0, fz-1.0),
+ noise_grad(hash(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0))));
+ return noise_scale3(result);
+}
+
+float noise(vec3 p)
+{
+ return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5;
+}
+
+float snoise(vec3 p)
+{
+ return noise_perlin(p.x, p.y, p.z);
+}
+
+float noise_turbulence(vec3 p, float octaves, int hard)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ int i, n;
+ octaves = clamp(octaves, 0.0, 16.0);
+ n = int(octaves);
+ for (i = 0; i <= n; i++) {
+ float t = noise(fscale*p);
+ if (hard != 0) {
+ t = abs(2.0*t - 1.0);
+ }
+ sum += t*amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale*p);
+ if (hard != 0) {
+ t = abs(2.0*t - 1.0);
+ }
+ float sum2 = sum + t*amp;
+ sum *= (float(1 << n) / float((1 << (n+1)) - 1));
+ sum2 *= (float(1 << (n+1)) / float((1 << (n+2)) - 1));
+ return (1.0 - rmd)*sum + rmd*sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n+1)) - 1));
+ return sum;
+ }
+}
+#endif // BIT_OPERATIONS
+
void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
{
+#ifdef BIT_OPERATIONS
+ vec3 p = co * scale;
+ int hard = 0;
+ if (distortion != 0.0) {
+ vec3 r, offset = vec3(13.5, 13.5, 13.5);
+ r.x = noise(p + offset) * distortion;
+ r.y = noise(p) * distortion;
+ r.z = noise(p - offset) * distortion;
+ p += r;
+ }
+
+ fac = noise_turbulence(p, detail, hard);
+ color = vec4(fac,
+ noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
+ noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
+ 1);
+#else // BIT_OPERATIONS
color = vec4(1.0);
fac = 1.0;
+#endif // BIT_OPERATIONS
+}
+
+
+#ifdef BIT_OPERATIONS
+
+/* Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for (i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ value += rmd * snoise(p) * pwr;
+
+ return value;
+}
+
+/* Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for (i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+
+ return value;
+}
+
+/* Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (i = 1; i < int(octaves); i++) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ result = snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0)
+ weight = 1.0;
+
+ signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ result += rmd * ((snoise(p) + offset) * pwr);
+
+ return result;
+}
+
+/* Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+float svm_musgrave(int type,
+ float dimension,
+ float lacunarity,
+ float octaves,
+ float offset,
+ float intensity,
+ float gain,
+ vec3 p)
+{
+ if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
+ return intensity*noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
+ else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
+ return intensity*noise_musgrave_fBm(p, dimension, lacunarity, octaves);
+ else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
+ return intensity*noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
+ return intensity*noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
+ return intensity*noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ return 0.0;
+}
+#endif // #ifdef BIT_OPERATIONS
+
+void node_tex_musgrave(vec3 co,
+ float scale,
+ float detail,
+ float dimension,
+ float lacunarity,
+ float offset,
+ float gain,
+ float type,
+ out vec4 color,
+ out float fac)
+{
+#ifdef BIT_OPERATIONS
+ fac = svm_musgrave(int(type),
+ dimension,
+ lacunarity,
+ detail,
+ offset,
+ 1.0,
+ gain,
+ co*scale);
+#else
+ fac = 1.0;
+#endif
+
+ color = vec4(fac, fac, fac, 1.0);
}
void node_tex_sky(vec3 co, out vec4 color)
@@ -2657,16 +3269,117 @@ void node_tex_sky(vec3 co, out vec4 color)
color = vec4(1.0);
}
-void node_tex_voronoi(vec3 co, float scale, out vec4 color, out float fac)
-{
+void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac)
+{
+#ifdef BIT_OPERATIONS
+ vec3 p = co * scale;
+ int xx, yy, zz, xi, yi, zi;
+ float da[4];
+ vec3 pa[4];
+
+ xi = floor_to_int(p[0]);
+ yi = floor_to_int(p[1]);
+ zi = floor_to_int(p[2]);
+
+ da[0] = 1e+10;
+ da[1] = 1e+10;
+ da[2] = 1e+10;
+ da[3] = 1e+10;
+
+ for (xx = xi - 1; xx <= xi + 1; xx++) {
+ for (yy = yi - 1; yy <= yi + 1; yy++) {
+ for (zz = zi - 1; zz <= zi + 1; zz++) {
+ vec3 ip = vec3(xx, yy, zz);
+ vec3 vp = cellnoise_color(ip);
+ vec3 pd = p - (vp + ip);
+ float d = dot(pd, pd);
+ vp += vec3(xx, yy, zz);
+ if (d < da[0]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = da[0];
+ da[0] = d;
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = pa[0];
+ pa[0] = vp;
+ }
+ else if (d < da[1]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = vp;
+ }
+ else if (d < da[2]) {
+ da[3] = da[2];
+ da[2] = d;
+
+ pa[3] = pa[2];
+ pa[2] = vp;
+ }
+ else if (d < da[3]) {
+ da[3] = d;
+ pa[3] = vp;
+ }
+ }
+ }
+ }
+
+ if (coloring == 0.0) {
+ fac = abs(da[0]);
+ color = vec4(fac, fac, fac, 1);
+ }
+ else {
+ color = vec4(cellnoise_color(pa[0]), 1);
+ fac = (color.x + color.y + color.z) * (1.0 / 3.0);
+ }
+#else // BIT_OPERATIONS
color = vec4(1.0);
fac = 1.0;
+#endif // BIT_OPERATIONS
}
-void node_tex_wave(vec3 co, float scale, float distortion, float detail, float detail_scale, out vec4 color, out float fac)
+#ifdef BIT_OPERATIONS
+float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
{
+ float n;
+
+ if (wave_type == 0) /* type bands */
+ n = (p.x + p.y + p.z) * 10.0;
+ else /* type rings */
+ n = length(p) * 20.0;
+
+ if (distortion != 0.0)
+ n += distortion * noise_turbulence(p*detail_scale, detail, 0);
+
+ if (wave_profile == 0) { /* profile sin */
+ return 0.5 + 0.5 * sin(n);
+ }
+ else { /* profile saw */
+ n /= 2.0 * M_PI;
+ n -= int(n);
+ return (n < 0.0)? n + 1.0: n;
+ }
+}
+#endif // BIT_OPERATIONS
+
+void node_tex_wave(
+ vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
+ out vec4 color, out float fac)
+{
+#ifdef BIT_OPERATIONS
+ float f;
+ f = calc_wave(co*scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+#else // BIT_OPERATIONS
color = vec4(1.0);
- fac = 1.0;
+ fac = 1;
+#endif // BIT_OPERATIONS
}
/* light path */
@@ -2720,9 +3433,30 @@ void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnorm
outnormal = normalize(outnormal);
}
-void node_bump(float strength, float dist, float height, vec3 N, out vec3 result)
+void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, float invert, out vec3 result)
{
- result = N;
+ if (invert != 0.0) {
+ dist *= -1.0;
+ }
+ vec3 dPdx = dFdx(surf_pos);
+ vec3 dPdy = dFdy(surf_pos);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, N);
+ vec3 Ry = cross(N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+ float absdet = abs(det);
+
+ float dHdx = dFdx(height);
+ float dHdy = dFdy(height);
+ vec3 surfgrad = dHdx*Rx + dHdy*Ry;
+
+ strength = max(strength, 0.0);
+
+ result = normalize(absdet*N - dist*sign(det)*surfgrad);
+ result = normalize(strength*result + (1.0 - strength)*N);
}
/* output */
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 7e332706695..5824d5a80db 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -29,7 +29,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
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/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/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/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_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 3807bb296fd..2d1ffaa53eb 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -75,6 +75,12 @@ typedef struct CustomData {
/* CustomData.type */
typedef enum CustomDataType {
+ /* Used by GLSL attributes in the cases when we need a delayed CD type
+ * assignment (in the cases when we don't know in advance which layer
+ * we are addressing).
+ */
+ CD_AUTO_FROM_NAME = -1,
+
CD_MVERT = 0,
#ifdef DNA_DEPRECATED
CD_MSTICKY = 1, /* DEPRECATED */
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_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 b0b113272c8..8066eabdffc 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1242,7 +1242,7 @@ typedef struct CurvePaintSettings {
int error_threshold;
float radius_min, radius_max;
float radius_taper_start, radius_taper_end;
- float radius_offset;
+ float surface_offset;
float corner_angle;
} CurvePaintSettings;
@@ -1251,6 +1251,7 @@ 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 */
@@ -1677,9 +1678,10 @@ typedef struct Scene {
#define R_STAMP_RENDERTIME 0x0400
#define R_STAMP_CAMERALENS 0x0800
#define R_STAMP_STRIPMETA 0x1000
+#define R_STAMP_MEMORY 0x2000
#define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \
R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \
- R_STAMP_RENDERTIME|R_STAMP_CAMERALENS)
+ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY)
/* alphamode */
#define R_ADDSKY 0
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 0ef8f2616c4..321ff26f68f 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -237,6 +237,13 @@ typedef struct View3D {
float stereo3d_convergence_factor;
float stereo3d_volume_alpha;
float stereo3d_convergence_alpha;
+
+ /* Previous viewport draw type.
+ * Runtime-only, set in the rendered viewport otggle operator.
+ */
+ short prev_drawtype;
+ short pad1;
+ float pad2;
} View3D;
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index a714518c32f..d714587d7ab 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -718,6 +718,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;
@@ -813,20 +835,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_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 e13919dd1a1..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;
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_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 6a993940513..5a3031d0514 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -196,6 +196,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,
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 59cdb75c8f0..bd14f206665 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5853,6 +5853,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_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 5bbc2b49a0d..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}
};
@@ -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 db1cf9bda89..a6fc7fecb28 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2620,6 +2620,10 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
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");
@@ -2650,7 +2654,7 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
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, "radius_offset", PROP_FLOAT, PROP_NONE);
+ 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");
@@ -5945,6 +5949,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "use_stamp_memory", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_MEMORY);
+ RNA_def_property_ui_text(prop, "Stamp Peak Memory", "Include the peak memory usage in image metadata");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "stamp_font_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "stamp_font_id");
RNA_def_property_range(prop, 8, 64);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 9ba50641cc0..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
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index c9f1b739660..0b8717fc982 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -687,6 +687,15 @@ static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
return drawtype;
}
+static void rna_SpaceView3D_viewport_shade_set(PointerRNA *ptr, int value)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ if (value != v3d->drawtype && value == OB_RENDER) {
+ v3d->prev_drawtype = v3d->drawtype;
+ }
+ v3d->drawtype = value;
+}
+
static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2402,7 +2411,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "viewport_shade", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "drawtype");
RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
- RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", NULL,
+ RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", "rna_SpaceView3D_viewport_shade_set",
"rna_SpaceView3D_viewport_shade_itemf");
RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_viewport_shade_update");
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_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 846e6747c1f..ef6b6e3de61 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 113c2cea33e..5439f77aede 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -340,7 +340,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 fa458cd20dc..7235a19a65e 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/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index c4ec55c8d06..29b1e5bc5c7 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -199,12 +199,172 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
+/* Find an output node of the shader tree.
+ *
+ * NOTE: it will only return output which is NOT in the group, which isn't how
+ * render engines works but it's how the GPU shader compilation works. This we
+ * can change in the future and make it a generic function, but for now it stays
+ * private here.
+ */
+static bNode *ntree_shader_output_node(bNodeTree *ntree)
+{
+ /* Make sure we only have single node tagged as output. */
+ ntreeSetOutput(ntree);
+ for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ if (node->flag & NODE_DO_OUTPUT) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+/* Find socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets,
+ const char *identifier)
+{
+ for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) {
+ if (STREQ(sock->identifier, identifier)) {
+ return sock;
+ }
+ }
+ return NULL;
+}
+
+/* Find input socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_input(bNode *node,
+ const char *identifier)
+{
+ return ntree_shader_node_find_socket(&node->inputs, identifier);
+}
+
+/* Find output socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_output(bNode *node,
+ const char *identifier)
+{
+ return ntree_shader_node_find_socket(&node->outputs, identifier);
+}
+
+/* Check whether shader has a displacement.
+ *
+ * Will also return a node and it's socket which is connected to a displacement
+ * output. Additionally, link which is attached to the displacement output is
+ * also returned.
+ */
+static bool ntree_shader_has_displacement(bNodeTree *ntree,
+ bNode **r_node,
+ bNodeSocket **r_socket,
+ bNodeLink **r_link)
+{
+ bNode *output_node = ntree_shader_output_node(ntree);
+ if (output_node == NULL) {
+ /* We can't have displacement without output node, apparently. */
+ return false;
+ }
+ /* Make sure sockets links pointers are correct. */
+ ntreeUpdateTree(G.main, ntree);
+ bNodeSocket *displacement = ntree_shader_node_find_input(output_node,
+ "Displacement");
+
+ if (displacement == NULL) {
+ /* Non-cycles node is used as an output. */
+ return false;
+ }
+ if (displacement->link != NULL) {
+ *r_node = displacement->link->fromnode;
+ *r_socket = displacement->link->fromsock;
+ *r_link = displacement->link;
+ }
+ return displacement->link != NULL;
+}
+
+/* Use specified node and socket as an input for unconnected normal sockets. */
+static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
+ bNode *node_from,
+ bNodeSocket *socket_from)
+{
+ for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ if (node == node_from) {
+ /* Don't connect node itself! */
+ continue;
+ }
+ bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
+ /* TODO(sergey): Can we do something smarter here than just a name-based
+ * matching?
+ */
+ if (sock == NULL) {
+ /* There's no Normal input, nothing to link. */
+ continue;
+ }
+ if (sock->link != NULL) {
+ /* Something is linked to the normal input already. can't
+ * use other input for that.
+ */
+ continue;
+ }
+ /* Create connection between specified node and the normal input. */
+ nodeAddLink(ntree, node_from, socket_from, node, sock);
+ }
+}
+
+/* Re-link displacement output to unconnected normal sockets via bump node.
+ * This way material with have proper displacement in the viewport.
+ */
+static void ntree_shader_relink_displacement(bNodeTree *ntree,
+ short compatibility)
+{
+ if (compatibility != NODE_NEW_SHADING) {
+ /* We can only deal with new shading system here. */
+ return;
+ }
+ bNode *displacement_node;
+ bNodeSocket *displacement_socket;
+ bNodeLink *displacement_link;
+ if (!ntree_shader_has_displacement(ntree,
+ &displacement_node,
+ &displacement_socket,
+ &displacement_link))
+ {
+ /* There is no displacement output connected, nothing to re-link. */
+ return;
+ }
+ /* We have to disconnect displacement output socket, otherwise we'll have
+ * cycles in the Cycles material :)
+ */
+ nodeRemLink(ntree, displacement_link);
+ /* We can't connect displacement to normal directly, use bump node for that
+ * and hope that it gives good enough approximation.
+ */
+ bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP);
+ bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
+ bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
+ BLI_assert(bump_input_socket != NULL);
+ BLI_assert(bump_output_socket != NULL);
+ /* Connect bump node to where displacement output was originally
+ * connected to.
+ */
+ nodeAddLink(ntree,
+ displacement_node, displacement_socket,
+ bump_node, bump_input_socket);
+ /* Connect all free-standing Normal inputs. */
+ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
+ /* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new
+ * bump node.
+ */
+ /* We modified the tree, it needs to be updated now. */
+ ntreeUpdateTree(G.main, ntree);
+}
+
void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)
{
/* localize tree to create links for reroute and mute */
bNodeTree *localtree = ntreeLocalize(ntree);
bNodeTreeExec *exec;
+ /* Perform all needed modifications on the tree in order to support
+ * displacement/bump mapping.
+ */
+ ntree_shader_relink_displacement(localtree, compatibility);
+
exec = ntreeShaderBeginExecTree(localtree);
ntreeExecGPUNodes(exec, mat, 1, compatibility);
ntreeShaderEndExecTree(exec);
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 61bdfb3dfd6..0a69593cf07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -45,9 +45,9 @@ static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
NodeShaderAttribute *attr = node->storage;
- GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->name);
+ GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, "node_attribute", in, out, mtface);
+ return GPU_stack_link(mat, "node_attribute", in, out, cd_attr);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 22027d58385..b39ca5d90ee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -45,14 +45,21 @@ static bNodeSocketTemplate sh_node_bump_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_bump(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_bump(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
-
- return GPU_stack_link(mat, "node_bump", in, out);
+ float invert = node->custom1;
+ GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&invert));
+ /* Other nodes are applying view matrix if the input Normal has a link.
+ * We don't want normal to have view matrix applied twice, so we cancel it here.
+ *
+ * TODO(sergey): This is an extra multiplication which cancels each other,
+ * better avoid this but that requires bigger refactor.
+ */
+ return GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index cd398cc8264..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)
{
@@ -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 642e5b296be..d2695609a88 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -121,35 +121,69 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
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);
- }
+ if (in[1].link)
+ realnorm = in[1].link;
+ else
+ realnorm = GPU_uniform(in[1].vec);
+ negnorm = GPU_builtin(GPU_VIEW_NORMAL);
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) {
+ if (GPU_material_use_new_shading_nodes(mat)) {
+
+ /* **************** CYCLES ******************** */
+
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+
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);
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
break;
case SHD_NORMAL_MAP_OBJECT:
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
+ break;
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_WORLD:
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ break;
case SHD_NORMAL_MAP_BLENDER_WORLD:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
break;
+
+ GPU_link(mat, "vect_normalize", realnorm, &realnorm);
}
- }
- 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);
+ } else {
+
+ /* *********** BLENDER INTERNAL *************** */
+
+ GPU_link(mat, "color_to_normal", realnorm, &realnorm);
+ GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
+ GPU_link(mat, "vec_math_negate", negnorm, &negnorm);
+
+ switch (nm->space) {
+ case SHD_NORMAL_MAP_TANGENT:
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
+ 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), &realnorm);
+ break;
+ case SHD_NORMAL_MAP_WORLD:
+ case SHD_NORMAL_MAP_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &realnorm);
+ break;
+ }
}
+ GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+
return true;
}
@@ -169,4 +203,3 @@ void register_node_type_sh_normal_map(void)
nodeRegisterType(&ntype);
}
-
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index 569eaf5ff9b..bb7f2166a8a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -64,12 +64,19 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
-
- return GPU_stack_link(mat, "node_tex_brick", in, out);
+ NodeTexBrick *tex = (NodeTexBrick *)node->storage;
+ float offset_freq = tex->offset_freq;
+ float squash_freq = tex->squash_freq;
+ return GPU_stack_link(mat, "node_tex_brick",
+ in, out,
+ GPU_uniform(&tex->offset), GPU_uniform(&offset_freq),
+ GPU_uniform(&tex->squash), GPU_uniform(&squash_freq));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index b7498df1706..77edd0e115e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -54,8 +54,10 @@ static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_checker(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
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 292221c9555..2f8f95b0675 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -82,7 +82,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
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_material_do_color_management(mat))
{
GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index 24916e8f013..18a8065fb57 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -52,12 +52,16 @@ static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_gradient(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_gradient", in, out);
+ NodeTexGradient *tex = (NodeTexGradient *)node->storage;
+ float gradient_type = tex->gradient_type;
+ return GPU_stack_link(mat, "node_tex_gradient", in, out, GPU_uniform(&gradient_type));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index 80904e376bc..8700d7954e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -57,8 +57,10 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat, bNode *node, bNodeExecDat
NodeTexMagic *tex = (NodeTexMagic *)node->storage;
float depth = tex->depth;
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 825ba7eb3c1..51d6699fadd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -58,12 +58,17 @@ static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_musgrave", in, out);
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ float type = tex->musgrave_type;
+
+ return GPU_stack_link(mat, "node_tex_musgrave", in, out, GPU_uniform(&type));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index d806140694e..91015b3db25 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -54,8 +54,10 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_noise(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index 88596a4a72f..c994798e2da 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -53,12 +53,17 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_voronoi", in, out);
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ float coloring = tex->coloring;
+
+ return GPU_stack_link(mat, "node_tex_voronoi", in, out, GPU_uniform(&coloring));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index 100510641e8..1194874e06c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -56,12 +56,18 @@ static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_wave(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_wave", in, out);
+ NodeTexWave *tex = (NodeTexWave *)node->storage;
+ float wave_type = tex->wave_type;
+ float wave_profile = tex->wave_profile;
+
+ return GPU_stack_link(mat, "node_tex_wave", in, out, GPU_uniform(&wave_type), GPU_uniform(&wave_profile));
}
/* 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 2ce38a068b7..6edf6c2a0b4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -127,7 +127,7 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
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_material_do_color_management(mat))
{
GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
}
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/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_driver.c b/source/blender/python/intern/bpy_driver.c
index 9cd6fe3da91..9b477e384db 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -347,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_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2ec73c3c9b7..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"
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/intern/gpu.c b/source/blender/python/intern/gpu.c
index 66c1ddcc352..c3bb588f7eb 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -261,6 +261,9 @@ static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObj
if (uniform->lamp) {
PY_DICT_ADD_ID(dict, uniform, lamp);
}
+ if (uniform->material) {
+ PY_DICT_ADD_ID(dict, uniform, material);
+ }
if (uniform->image) {
PY_DICT_ADD_ID(dict, uniform, image);
}
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/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/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 00aee47b5e6..2af2449c4ba 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2859,7 +2859,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/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index ad8c31a32f3..4f9d48450f6 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2359,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;
@@ -2897,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;
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5041eebd126..2e4a4b63b7a 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -405,18 +405,38 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* 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);
+ 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);
@@ -493,5 +513,8 @@ void WM_OT_append(wmOperatorType *ot)
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, "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_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index e4ba3969824..6ef8965a408 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2845,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 {
@@ -2871,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);
@@ -2879,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);
}
}
@@ -4296,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");
}
@@ -4330,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/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 */