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-07-12 01:01:38 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-07-12 01:07:44 +0300
commitcfbd605567f48229a923df382baf6db98fbafc61 (patch)
treed4218c49672047d6c3b37517034660b3b5dcd966
parent71a57a37b2eebbed53b5335019287b4df9c30519 (diff)
parent7212ebd09f9720883581221be923ae5e97ff5d76 (diff)
Merge branch 'master' into blender2.8
Conflicts: intern/cycles/blender/addon/ui.py source/blender/blenkernel/BKE_particle.h source/blender/blenkernel/intern/dynamicpaint.c source/blender/blenkernel/intern/library.c source/blender/blenkernel/intern/object.c source/blender/blenkernel/intern/particle.c source/blender/blenkernel/intern/particle_distribute.c source/blender/blenkernel/intern/texture.c source/blender/editors/object/object_add.c source/blender/editors/object/object_relations.c source/blender/editors/physics/particle_edit.c source/blender/editors/physics/particle_object.c source/blender/editors/transform/transform_snap_object.c
-rwxr-xr-xbuild_files/build_environment/install_deps.sh4
-rw-r--r--build_files/package_spec/pacman/PKGBUILD10
-rw-r--r--extern/CMakeLists.txt8
-rw-r--r--intern/cycles/blender/addon/ui.py144
-rw-r--r--intern/cycles/blender/blender_shader.cpp2
-rw-r--r--intern/cycles/bvh/CMakeLists.txt2
-rw-r--r--intern/cycles/bvh/bvh.cpp595
-rw-r--r--intern/cycles/bvh/bvh.h50
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp72
-rw-r--r--intern/cycles/bvh/bvh_binning.h39
-rw-r--r--intern/cycles/bvh/bvh_build.cpp270
-rw-r--r--intern/cycles/bvh/bvh_build.h27
-rw-r--r--intern/cycles/bvh/bvh_node.cpp70
-rw-r--r--intern/cycles/bvh/bvh_node.h47
-rw-r--r--intern/cycles/bvh/bvh_params.h18
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp43
-rw-r--r--intern/cycles/bvh/bvh_sort.h10
-rw-r--r--intern/cycles/bvh/bvh_split.cpp115
-rw-r--r--intern/cycles/bvh/bvh_split.h82
-rw-r--r--intern/cycles/bvh/bvh_unaligned.cpp178
-rw-r--r--intern/cycles/bvh/bvh_unaligned.h81
-rw-r--r--intern/cycles/kernel/CMakeLists.txt39
-rw-r--r--intern/cycles/kernel/bvh/bvh.h (renamed from intern/cycles/kernel/geom/geom_bvh.h)63
-rw-r--r--intern/cycles/kernel/bvh/bvh_nodes.h656
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h (renamed from intern/cycles/kernel/geom/geom_bvh_shadow.h)260
-rw-r--r--intern/cycles/kernel/bvh/bvh_subsurface.h (renamed from intern/cycles/kernel/geom/geom_bvh_subsurface.h)177
-rw-r--r--intern/cycles/kernel/bvh/bvh_traversal.h (renamed from intern/cycles/kernel/geom/geom_bvh_traversal.h)337
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume.h (renamed from intern/cycles/kernel/geom/geom_bvh_volume.h)221
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h (renamed from intern/cycles/kernel/geom/geom_bvh_volume_all.h)235
-rw-r--r--intern/cycles/kernel/bvh/qbvh_nodes.h433
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h (renamed from intern/cycles/kernel/geom/geom_qbvh_shadow.h)296
-rw-r--r--intern/cycles/kernel/bvh/qbvh_subsurface.h (renamed from intern/cycles/kernel/geom/geom_qbvh_subsurface.h)194
-rw-r--r--intern/cycles/kernel/bvh/qbvh_traversal.h505
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume.h (renamed from intern/cycles/kernel/geom/geom_qbvh_volume.h)249
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h (renamed from intern/cycles/kernel/geom/geom_qbvh_volume_all.h)263
-rw-r--r--intern/cycles/kernel/geom/geom.h22
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h4
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h32
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh.h147
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_traversal.h412
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h61
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h28
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h1
-rw-r--r--intern/cycles/kernel/kernel_light.h4
-rw-r--r--intern/cycles/kernel/kernel_path.h1
-rw-r--r--intern/cycles/kernel/kernel_random.h2
-rw-r--r--intern/cycles/kernel/kernel_textures.h6
-rw-r--r--intern/cycles/kernel/kernel_types.h27
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel.cl1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp5
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl14
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_to_bw.osl25
-rw-r--r--intern/cycles/kernel/split/kernel_split_common.h1
-rw-r--r--intern/cycles/kernel/svm/svm_image.h37
-rw-r--r--intern/cycles/render/image.cpp35
-rw-r--r--intern/cycles/render/image.h2
-rw-r--r--intern/cycles/render/mesh.cpp221
-rw-r--r--intern/cycles/render/mesh.h57
-rw-r--r--intern/cycles/render/nodes.cpp10
-rw-r--r--intern/cycles/render/scene.h6
-rw-r--r--intern/cycles/util/util_boundbox.h2
-rw-r--r--intern/cycles/util/util_transform.h13
-rw-r--r--intern/cycles/util/util_types.h1
-rw-r--r--intern/decklink/DeckLinkAPI.cpp16
-rw-r--r--intern/decklink/DeckLinkAPI.h16
-rw-r--r--intern/gpudirect/dvpapi.cpp54
-rw-r--r--intern/gpudirect/dvpapi.h54
-rw-r--r--release/scripts/startup/bl_operators/object.py85
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py38
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py27
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py3
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py1
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py14
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py14
-rw-r--r--source/blender/blenkernel/BKE_action.h5
-rw-r--r--source/blender/blenkernel/BKE_animsys.h3
-rw-r--r--source/blender/blenkernel/BKE_armature.h4
-rw-r--r--source/blender/blenkernel/BKE_brush.h4
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h12
-rw-r--r--source/blender/blenkernel/BKE_camera.h4
-rw-r--r--source/blender/blenkernel/BKE_curve.h14
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h3
-rw-r--r--source/blender/blenkernel/BKE_group.h2
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_key.h5
-rw-r--r--source/blender/blenkernel/BKE_lamp.h4
-rw-r--r--source/blender/blenkernel/BKE_lattice.h4
-rw-r--r--source/blender/blenkernel/BKE_library.h8
-rw-r--r--source/blender/blenkernel/BKE_library_query.h14
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h10
-rw-r--r--source/blender/blenkernel/BKE_mask.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h8
-rw-r--r--source/blender/blenkernel/BKE_mball.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h10
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_speaker.h4
-rw-r--r--source/blender/blenkernel/BKE_texture.h4
-rw-r--r--source/blender/blenkernel/BKE_world.h4
-rw-r--r--source/blender/blenkernel/intern/action.c87
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c48
-rw-r--r--source/blender/blenkernel/intern/armature.c59
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c81
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c71
-rw-r--r--source/blender/blenkernel/intern/camera.c58
-rw-r--r--source/blender/blenkernel/intern/colortools.c2
-rw-r--r--source/blender/blenkernel/intern/constraint.c4
-rw-r--r--source/blender/blenkernel/intern/curve.c146
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c6
-rw-r--r--source/blender/blenkernel/intern/gpencil.c5
-rw-r--r--source/blender/blenkernel/intern/group.c9
-rw-r--r--source/blender/blenkernel/intern/image.c163
-rw-r--r--source/blender/blenkernel/intern/key.c33
-rw-r--r--source/blender/blenkernel/intern/lamp.c71
-rw-r--r--source/blender/blenkernel/intern/lattice.c68
-rw-r--r--source/blender/blenkernel/intern/library.c138
-rw-r--r--source/blender/blenkernel/intern/library_query.c215
-rw-r--r--source/blender/blenkernel/intern/library_remap.c304
-rw-r--r--source/blender/blenkernel/intern/linestyle.c7
-rw-r--r--source/blender/blenkernel/intern/mask.c19
-rw-r--r--source/blender/blenkernel/intern/material.c226
-rw-r--r--source/blender/blenkernel/intern/mball.c67
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh.c146
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c8
-rw-r--r--source/blender/blenkernel/intern/nla.c4
-rw-r--r--source/blender/blenkernel/intern/node.c86
-rw-r--r--source/blender/blenkernel/intern/object.c118
-rw-r--r--source/blender/blenkernel/intern/object_update.c4
-rw-r--r--source/blender/blenkernel/intern/packedFile.c6
-rw-r--r--source/blender/blenkernel/intern/pbvh.c39
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c497
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/scene.c20
-rw-r--r--source/blender/blenkernel/intern/softbody.c2
-rw-r--r--source/blender/blenkernel/intern/speaker.c64
-rw-r--r--source/blender/blenkernel/intern/text.c5
-rw-r--r--source/blender/blenkernel/intern/texture.c178
-rw-r--r--source/blender/blenkernel/intern/world.c62
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h13
-rw-r--r--source/blender/blenlib/BLI_math_geom.h7
-rw-r--r--source/blender/blenlib/BLI_math_vector.h10
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c416
-rw-r--r--source/blender/blenlib/intern/array_store.c14
-rw-r--r--source/blender/blenlib/intern/math_geom.c61
-rw-r--r--source/blender/blenlib/intern/math_interp.c32
-rw-r--r--source/blender/blenlib/intern/math_rotation.c3
-rw-r--r--source/blender/blenlib/intern/math_vector.c21
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c34
-rw-r--r--source/blender/blenloader/intern/readfile.c8
-rw-r--r--source/blender/blenloader/intern/undofile.c16
-rw-r--r--source/blender/blenloader/intern/versioning_250.c2
-rw-r--r--source/blender/blenloader/intern/writefile.c148
-rw-r--r--source/blender/bmesh/bmesh_class.h47
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c22
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c35
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c333
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h21
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h77
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api_inline.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c128
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c10
-rw-r--r--source/blender/bmesh/operators/bmo_beautify.c6
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c12
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c28
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c8
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c6
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c29
-rw-r--r--source/blender/bmesh/operators/bmo_create.c29
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c78
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c52
-rw-r--r--source/blender/bmesh/operators/bmo_edgenet.c14
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c84
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c16
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c4
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c79
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c4
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c12
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c20
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c10
-rw-r--r--source/blender/bmesh/operators/bmo_planar_faces.c14
-rw-r--r--source/blender/bmesh/operators/bmo_poke.c4
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c80
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c52
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c68
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c63
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c58
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c16
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c80
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c18
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c4
-rw-r--r--source/blender/collada/DocumentImporter.cpp2
-rw-r--r--source/blender/collada/collada_utils.cpp19
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h6
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc28
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c12
-rw-r--r--source/blender/editors/animation/anim_filter.c198
-rw-r--r--source/blender/editors/animation/keyframes_draw.c171
-rw-r--r--source/blender/editors/animation/keyframes_edit.c10
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_lib.c4
-rw-r--r--source/blender/editors/curve/editcurve.c7
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c4
-rw-r--r--source/blender/editors/include/ED_anim_api.h14
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h26
-rw-r--r--source/blender/editors/include/UI_icons.h1
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c67
-rw-r--r--source/blender/editors/interface/interface_icons.c6
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_regions.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c16
-rw-r--r--source/blender/editors/interface/interface_widgets.c2
-rw-r--r--source/blender/editors/interface/resources.c34
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c3
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c3
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c205
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c6
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c35
-rw-r--r--source/blender/editors/mesh/mesh_data.c6
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c17
-rw-r--r--source/blender/editors/object/object_add.c88
-rw-r--r--source/blender/editors/object/object_constraint.c4
-rw-r--r--source/blender/editors/object/object_data_transfer.c6
-rw-r--r--source/blender/editors/object/object_edit.c12
-rw-r--r--source/blender/editors/object/object_group.c2
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_ops.c18
-rw-r--r--source/blender/editors/object/object_relations.c88
-rw-r--r--source/blender/editors/object/object_shapekey.c9
-rw-r--r--source/blender/editors/object/object_transform.c134
-rw-r--r--source/blender/editors/object/object_vgroup.c23
-rw-r--r--source/blender/editors/render/render_preview.c4
-rw-r--r--source/blender/editors/render/render_shading.c6
-rw-r--r--source/blender/editors/screen/screen_ops.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_action/action_data.c2
-rw-r--r--source/blender/editors/space_action/action_draw.c64
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_select.c24
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_graph/graph_draw.c18
-rw-r--r--source/blender/editors/space_graph/space_graph.c236
-rw-r--r--source/blender/editors/space_logic/logic_ops.c6
-rw-r--r--source/blender/editors/space_nla/nla_draw.c62
-rw-r--r--source/blender/editors/space_nla/nla_edit.c6
-rw-r--r--source/blender/editors/space_node/node_group.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c13
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c86
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h56
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c222
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c2
-rw-r--r--source/blender/editors/space_text/text_ops.c6
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c5
-rw-r--r--source/blender/editors/space_view3d/drawobject.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c5
-rw-r--r--source/blender/editors/transform/transform.c26
-rw-r--r--source/blender/editors/transform/transform_constraints.c9
-rw-r--r--source/blender/editors/transform/transform_conversions.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c6
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1205
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c8
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.h14
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h6
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h10
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h4
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.h6
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h14
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/Functions0D.h12
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h6
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp32
-rw-r--r--source/blender/gpu/GPU_buffers.h4
-rw-r--r--source/blender/gpu/GPU_material.h1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c4
-rw-r--r--source/blender/gpu/intern/gpu_material.c39
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl14
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c31
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.h2
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp4
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.h2
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_action_types.h5
-rw-r--r--source/blender/makesdna/DNA_curve_types.h1
-rw-r--r--source/blender/makesdna/DNA_genfile.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c20
-rw-r--r--source/blender/makesrna/intern/rna_ID.c5
-rw-r--r--source/blender/makesrna/intern/rna_access.c6
-rw-r--r--source/blender/makesrna/intern/rna_action.c11
-rw-r--r--source/blender/makesrna/intern/rna_define.c2
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c3
-rw-r--r--source/blender/makesrna/intern/rna_object.c6
-rw-r--r--source/blender/makesrna/intern/rna_scene.c17
-rw-r--r--source/blender/makesrna/intern/rna_space.c6
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c7
-rw-r--r--source/blender/makesrna/intern/rna_world.c25
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c52
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c3
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c19
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c22
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c6
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c2
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/render/intern/include/pixelblending.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp6
-rw-r--r--source/blender/render/intern/source/convertblender.c3
-rw-r--r--source/blender/render/intern/source/envmap.c28
-rw-r--r--source/blender/render/intern/source/multires_bake.c3
-rw-r--r--source/blender/render/intern/source/pipeline.c140
-rw-r--r--source/blender/render/intern/source/pixelblending.c16
-rw-r--r--source/blender/render/intern/source/render_texture.c18
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c12
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c15
-rw-r--r--source/creator/CMakeLists.txt22
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp8
-rw-r--r--source/gameengine/Converter/BL_ShapeDeformer.cpp6
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp6
-rw-r--r--source/gameengine/Expressions/intern/IntValue.cpp22
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp4
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp12
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp2
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h10
-rw-r--r--source/gameengine/Rasterizer/RAS_IOffScreen.h12
-rw-r--r--source/gameengine/Rasterizer/RAS_ISync.h12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h12
-rw-r--r--source/gameengine/VideoTexture/DeckLink.cpp12
-rw-r--r--source/gameengine/VideoTexture/DeckLink.h12
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp12
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.h12
-rw-r--r--tests/gtests/bmesh/bmesh_core_test.cc4
-rwxr-xr-xtests/python/cycles_render_tests.py3
387 files changed, 11214 insertions, 6462 deletions
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index e380362a11e..068ac665623 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -321,7 +321,7 @@ LLVM_FORCE_REBUILD=false
LLVM_SKIP=false
# OSL needs to be compiled for now!
-OSL_VERSION="1.7.1"
+OSL_VERSION="1.7.3"
OSL_VERSION_MIN=$OSL_VERSION
OSL_FORCE_BUILD=false
OSL_FORCE_REBUILD=false
@@ -1742,7 +1742,7 @@ compile_OSL() {
fi
# To be changed each time we make edits that would modify the compiled result!
- osl_magic=20
+ osl_magic=21
_init_osl
# Clean install if needed!
diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD
index 961e35578b9..aea5acd13e4 100644
--- a/build_files/package_spec/pacman/PKGBUILD
+++ b/build_files/package_spec/pacman/PKGBUILD
@@ -2,11 +2,9 @@
# custom blender vars
blender_srcdir=$(dirname $startdir)"/../.."
-# value may be formatted: 35042:35051M
-blender_revision=$(svnversion $blender_srcdir | cut -d: -f2 | awk '{print $3}')
-blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}')
+blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h | awk '{print $3}')
blender_version=$(expr $blender_version / 100).$(expr $blender_version % 100) # 256 -> 2.56
-blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender.h)
+blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h)
# blender_subversion=$(grep BLENDER_SUBVERSION $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}')
# map the version a -> 1
@@ -27,7 +25,9 @@ arch=('i686' 'x86_64')
url="www.blender.org"
license=('GPL')
groups=()
-depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.4' 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' 'libsndfile' 'ffmpeg')
+depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.5'
+ 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl'
+ 'libsndfile' 'ffmpeg')
makedepends=('cmake' 'git')
optdepends=()
provides=()
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 58e0c68148b..b046e9626b6 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -29,6 +29,14 @@ add_subdirectory(curve_fit_nd)
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
+# Not a strict flag, but noisy for code we don't maintain
+if(CMAKE_COMPILER_IS_GNUCC)
+ remove_cc_flag(
+ "-Wmisleading-indentation"
+ )
+endif()
+
+
add_subdirectory(rangetree)
add_subdirectory(wcwidth)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 94ed3dd4311..3c9c83fec42 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -383,7 +383,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
sub.prop(cscene, "use_progressive_refine")
subsub = sub.column(align=True)
- subsub.enabled = not rd.use_border
subsub.prop(rd, "use_save_buffers")
col = split.column(align=True)
@@ -1599,89 +1598,62 @@ def draw_pause(self, context):
def get_panels():
- types = bpy.types
- panels = [
- "RENDER_PT_render",
- "RENDER_PT_output",
- "RENDER_PT_encoding",
- "RENDER_PT_dimensions",
- "RENDER_PT_stamp",
- "RENDER_PT_freestyle",
- "RENDERLAYER_PT_layers",
- "RENDERLAYER_PT_freestyle",
- "RENDERLAYER_PT_freestyle_lineset",
- "RENDERLAYER_PT_freestyle_linestyle",
- "SCENE_PT_scene",
- "SCENE_PT_color_management",
- "SCENE_PT_custom_props",
- "SCENE_PT_audio",
- "SCENE_PT_unit",
- "SCENE_PT_keying_sets",
- "SCENE_PT_keying_set_paths",
- "SCENE_PT_physics",
- "WORLD_PT_context_world",
- "WORLD_PT_custom_props",
- "DATA_PT_context_mesh",
- "DATA_PT_context_camera",
- "DATA_PT_context_lamp",
- "DATA_PT_context_speaker",
- "DATA_PT_normals",
- "DATA_PT_texture_space",
- "DATA_PT_curve_texture_space",
- "DATA_PT_mball_texture_space",
- "DATA_PT_vertex_groups",
- "DATA_PT_shape_keys",
- "DATA_PT_uv_texture",
- "DATA_PT_vertex_colors",
- "DATA_PT_camera",
- "DATA_PT_camera_display",
- "DATA_PT_camera_stereoscopy",
- "DATA_PT_camera_safe_areas",
- "DATA_PT_lens",
- "DATA_PT_speaker",
- "DATA_PT_distance",
- "DATA_PT_cone",
- "DATA_PT_customdata",
- "DATA_PT_custom_props_mesh",
- "DATA_PT_custom_props_camera",
- "DATA_PT_custom_props_lamp",
- "DATA_PT_custom_props_speaker",
- "DATA_PT_custom_props_arm",
- "DATA_PT_custom_props_curve",
- "DATA_PT_custom_props_lattice",
- "DATA_PT_custom_props_metaball",
- "TEXTURE_PT_preview",
- "TEXTURE_PT_custom_props",
- "TEXTURE_PT_clouds",
- "TEXTURE_PT_wood",
- "TEXTURE_PT_marble",
- "TEXTURE_PT_magic",
- "TEXTURE_PT_blend",
- "TEXTURE_PT_stucci",
- "TEXTURE_PT_image",
- "TEXTURE_PT_image_sampling",
- "TEXTURE_PT_image_mapping",
- "TEXTURE_PT_musgrave",
- "TEXTURE_PT_voronoi",
- "TEXTURE_PT_distortednoise",
- "TEXTURE_PT_voxeldata",
- "TEXTURE_PT_pointdensity",
- "TEXTURE_PT_pointdensity_turbulence",
- "TEXTURE_PT_mapping",
- "TEXTURE_PT_ocean",
- "TEXTURE_PT_influence",
- "TEXTURE_PT_colors",
- "SCENE_PT_rigid_body_world",
- "SCENE_PT_rigid_body_cache",
- "SCENE_PT_rigid_body_field_weights",
- "MATERIAL_PT_custom_props",
- "MATERIAL_PT_freestyle_line",
- "BONE_PT_custom_props",
- "OBJECT_PT_custom_props",
- ]
-
- return [getattr(types, p) for p in panels if hasattr(types, p)]
-
+ exclude_panels = {
+ 'DATA_PT_area',
+ 'DATA_PT_camera_dof',
+ 'DATA_PT_falloff_curve',
+ 'DATA_PT_lamp',
+ 'DATA_PT_preview',
+ 'DATA_PT_shadow',
+ 'DATA_PT_spot',
+ 'DATA_PT_sunsky',
+ 'MATERIAL_PT_context_material',
+ 'MATERIAL_PT_diffuse',
+ 'MATERIAL_PT_flare',
+ 'MATERIAL_PT_halo',
+ 'MATERIAL_PT_mirror',
+ 'MATERIAL_PT_options',
+ 'MATERIAL_PT_pipeline',
+ 'MATERIAL_PT_preview',
+ 'MATERIAL_PT_shading',
+ 'MATERIAL_PT_shadow',
+ 'MATERIAL_PT_specular',
+ 'MATERIAL_PT_sss',
+ 'MATERIAL_PT_strand',
+ 'MATERIAL_PT_transp',
+ 'MATERIAL_PT_volume_density',
+ 'MATERIAL_PT_volume_integration',
+ 'MATERIAL_PT_volume_lighting',
+ 'MATERIAL_PT_volume_options',
+ 'MATERIAL_PT_volume_shading',
+ 'MATERIAL_PT_volume_transp',
+ 'RENDERLAYER_PT_layer_options',
+ 'RENDERLAYER_PT_layer_passes',
+ 'RENDERLAYER_PT_views',
+ 'RENDER_PT_antialiasing',
+ 'RENDER_PT_bake',
+ 'RENDER_PT_motion_blur',
+ 'RENDER_PT_performance',
+ 'RENDER_PT_post_processing',
+ 'RENDER_PT_shading',
+ 'SCENE_PT_simplify',
+ 'TEXTURE_PT_context_texture',
+ 'WORLD_PT_ambient_occlusion',
+ 'WORLD_PT_environment_lighting',
+ 'WORLD_PT_gather',
+ 'WORLD_PT_indirect_lighting',
+ 'WORLD_PT_mist',
+ 'WORLD_PT_preview',
+ 'WORLD_PT_world'
+ }
+
+ panels = []
+ for panel in bpy.types.Panel.__subclasses__():
+ if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
+ if panel.__name__ not in exclude_panels:
+ panels.append(panel)
+
+ return panels
def register():
bpy.types.RENDER_PT_render.append(draw_device)
@@ -1690,10 +1662,10 @@ def register():
for panel in get_panels():
panel.COMPAT_ENGINES.add('CYCLES')
-
def unregister():
bpy.types.RENDER_PT_render.remove(draw_device)
bpy.types.VIEW3D_HT_header.remove(draw_pause)
for panel in get_panels():
- panel.COMPAT_ENGINES.remove('CYCLES')
+ if 'CYCLES' in panel.COMPAT_ENGINES:
+ panel.COMPAT_ENGINES.remove('CYCLES')
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 7ca23f23cb4..64559804ccb 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -440,7 +440,7 @@ static ShaderNode *add_node(Scene *scene,
glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
- glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
+ glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index 5729fa6113d..92e48f0d87f 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -19,6 +19,7 @@ set(SRC
bvh_node.cpp
bvh_sort.cpp
bvh_split.cpp
+ bvh_unaligned.cpp
)
set(SRC_HEADERS
@@ -29,6 +30,7 @@ set(SRC_HEADERS
bvh_params.h
bvh_sort.h
bvh_split.h
+ bvh_unaligned.h
)
include_directories(${INC})
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index fa2b9ae7279..e92526ac1c4 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -24,6 +24,7 @@
#include "bvh_build.h"
#include "bvh_node.h"
#include "bvh_params.h"
+#include "bvh_unaligned.h"
#include "util_debug.h"
#include "util_foreach.h"
@@ -121,7 +122,7 @@ void BVH::refit(Progress& progress)
/* Triangles */
-void BVH::pack_triangle(int idx, float4 storage[3])
+void BVH::pack_triangle(int idx, float4 tri_verts[3])
{
int tob = pack.prim_object[idx];
assert(tob >= 0 && tob < objects.size());
@@ -129,49 +130,58 @@ void BVH::pack_triangle(int idx, float4 storage[3])
int tidx = pack.prim_index[idx];
Mesh::Triangle t = mesh->get_triangle(tidx);
- const float3* vpos = &mesh->verts[0];
+ const float3 *vpos = &mesh->verts[0];
float3 v0 = vpos[t.v[0]];
float3 v1 = vpos[t.v[1]];
float3 v2 = vpos[t.v[2]];
- storage[0] = float3_to_float4(v0);
- storage[1] = float3_to_float4(v1);
- storage[2] = float3_to_float4(v2);
+ tri_verts[0] = float3_to_float4(v0);
+ tri_verts[1] = float3_to_float4(v1);
+ tri_verts[2] = float3_to_float4(v2);
}
void BVH::pack_primitives()
{
- int nsize = TRI_NODE_SIZE;
- size_t tidx_size = pack.prim_index.size();
-
- pack.tri_storage.clear();
- pack.tri_storage.resize(tidx_size * nsize);
+ const size_t tidx_size = pack.prim_index.size();
+ size_t num_prim_triangles = 0;
+ /* Count number of triangles primitives in BVH. */
+ for(unsigned int i = 0; i < tidx_size; i++) {
+ if((pack.prim_index[i] != -1)) {
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ ++num_prim_triangles;
+ }
+ }
+ }
+ /* Reserve size for arrays. */
+ pack.prim_tri_index.clear();
+ pack.prim_tri_index.resize(tidx_size);
+ pack.prim_tri_verts.clear();
+ pack.prim_tri_verts.resize(num_prim_triangles * 3);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
-
+ /* Fill in all the arrays. */
+ size_t prim_triangle_index = 0;
for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) {
- float4 storage[3];
+ int tob = pack.prim_object[i];
+ Object *ob = objects[tob];
- if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
- pack_triangle(i, storage);
+ if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]);
+ pack.prim_tri_index[i] = 3 * prim_triangle_index;
+ ++prim_triangle_index;
}
else {
- /* Avoid use of uninitialized memory. */
- memset(&storage, 0, sizeof(storage));
+ pack.prim_tri_index[i] = -1;
}
- memcpy(&pack.tri_storage[i * nsize], storage, sizeof(float4)*3);
-
- int tob = pack.prim_object[i];
- Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
pack.prim_visibility[i] |= PATH_RAY_CURVE;
}
else {
- memset(&pack.tri_storage[i * nsize], 0, sizeof(float4)*3);
+ pack.prim_tri_index[i] = -1;
pack.prim_visibility[i] = 0;
}
}
@@ -183,13 +193,13 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
{
/* The BVH's for instances are built separately, but for traversal all
* BVH's are stored in global arrays. This function merges them into the
- * top level BVH, adjusting indexes and offsets where appropriate. */
- bool use_qbvh = params.use_qbvh;
- size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
- size_t nsize_leaf = (use_qbvh)? BVH_QNODE_LEAF_SIZE: BVH_NODE_LEAF_SIZE;
+ * top level BVH, adjusting indexes and offsets where appropriate.
+ */
+ const bool use_qbvh = params.use_qbvh;
- /* adjust primitive index to point to the triangle in the global array, for
- * meshes with transform applied and already in the top level BVH */
+ /* Adjust primitive index to point to the triangle in the global array, for
+ * meshes with transform applied and already in the top level BVH.
+ */
for(size_t i = 0; i < pack.prim_index.size(); i++)
if(pack.prim_index[i] != -1) {
if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
@@ -208,10 +218,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* reserve */
size_t prim_index_size = pack.prim_index.size();
- size_t tri_storage_size = pack.tri_storage.size();
+ size_t prim_tri_verts_size = pack.prim_tri_verts.size();
size_t pack_prim_index_offset = prim_index_size;
- size_t pack_tri_storage_offset = tri_storage_size;
+ size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
size_t pack_nodes_offset = nodes_size;
size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
@@ -225,7 +235,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
if(mesh->need_build_bvh()) {
if(mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
- tri_storage_size += bvh->pack.tri_storage.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
nodes_size += bvh->pack.nodes.size();
leaf_nodes_size += bvh->pack.leaf_nodes.size();
@@ -240,7 +250,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
- pack.tri_storage.resize(tri_storage_size);
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ pack.prim_tri_index.resize(prim_index_size);
pack.nodes.resize(nodes_size);
pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
@@ -249,7 +260,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
- float4 *pack_tri_storage = (pack.tri_storage.size())? &pack.tri_storage[0]: NULL;
+ float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL;
+ uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL;
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL;
@@ -277,8 +289,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
BVH *bvh = mesh->bvh;
- int noffset = nodes_offset/nsize;
- int noffset_leaf = nodes_leaf_offset/nsize_leaf;
+ int noffset = nodes_offset;
+ int noffset_leaf = nodes_leaf_offset;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
@@ -290,18 +302,24 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
mesh_map[mesh] = pack.object_node[object_offset-1];
- /* merge primitive and object indexes */
+ /* merge primitive, object and triangle indexes */
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
int *bvh_prim_type = &bvh->pack.prim_type[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
+ uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
for(size_t i = 0; i < bvh_prim_index_size; i++) {
- if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
+ if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
- else
+ pack_prim_tri_index[pack_prim_index_offset] = -1;
+ }
+ else {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ pack_prim_tri_index[pack_prim_index_offset] =
+ bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
+ }
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
@@ -310,50 +328,64 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
}
}
- /* merge triangle intersection data */
- if(bvh->pack.tri_storage.size()) {
- memcpy(pack_tri_storage + pack_tri_storage_offset,
- &bvh->pack.tri_storage[0],
- bvh->pack.tri_storage.size()*sizeof(float4));
- pack_tri_storage_offset += bvh->pack.tri_storage.size();
+ /* Merge triangle vertices data. */
+ if(bvh->pack.prim_tri_verts.size()) {
+ const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+ &bvh->pack.prim_tri_verts[0],
+ prim_tri_size*sizeof(float4));
+ pack_prim_tri_verts_offset += prim_tri_size;
}
/* merge nodes */
if(bvh->pack.leaf_nodes.size()) {
int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
- for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; i+=nsize_leaf, j++) {
+ for(size_t i = 0, j = 0;
+ i < leaf_nodes_offset_size;
+ i+= BVH_NODE_LEAF_SIZE, j++)
+ {
int4 data = leaf_nodes_offset[i];
data.x += prim_offset;
data.y += prim_offset;
pack_leaf_nodes[pack_leaf_nodes_offset] = data;
- for(int j = 1; j < nsize_leaf; ++j) {
+ for(int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
}
- pack_leaf_nodes_offset += nsize_leaf;
+ pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
}
}
if(bvh->pack.nodes.size()) {
- /* For QBVH we're packing a child bbox into 6 float4,
- * and for regular BVH they're packed into 3 float4.
- */
- size_t nsize_bbox = (use_qbvh)? 6: 3;
int4 *bvh_nodes = &bvh->pack.nodes[0];
- size_t bvh_nodes_size = bvh->pack.nodes.size();
+ size_t bvh_nodes_size = bvh->pack.nodes.size();
+
+ for(size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
+ size_t nsize, nsize_bbox;
+ if(bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
+ nsize = use_qbvh
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_UNALIGNED_NODE_SIZE;
+ nsize_bbox = (use_qbvh)? 13: 0;
+ }
+ else {
+ nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
+ nsize_bbox = (use_qbvh)? 7: 0;
+ }
- for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
- memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
+ memcpy(pack_nodes + pack_nodes_offset,
+ bvh_nodes + i,
+ nsize_bbox*sizeof(int4));
- /* modify offsets into arrays */
+ /* Modify offsets into arrays */
int4 data = bvh_nodes[i + nsize_bbox];
- data.x += (data.x < 0)? -noffset_leaf: noffset;
- data.y += (data.y < 0)? -noffset_leaf: noffset;
+ data.z += (data.z < 0)? -noffset_leaf: noffset;
+ data.w += (data.w < 0)? -noffset_leaf: noffset;
if(use_qbvh) {
- data.z += (data.z < 0)? -noffset_leaf: noffset;
- data.w += (data.w < 0)? -noffset_leaf: noffset;
+ data.x += (data.x < 0)? -noffset_leaf: noffset;
+ data.y += (data.y < 0)? -noffset_leaf: noffset;
}
pack_nodes[pack_nodes_offset + nsize_bbox] = data;
@@ -366,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
sizeof(int4) * (nsize - (nsize_bbox+1)));
pack_nodes_offset += nsize;
+ i += nsize;
}
}
@@ -377,12 +410,20 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* Regular BVH */
+static bool node_bvh_is_unaligned(const BVHNode *node)
+{
+ const BVHNode *node0 = node->get_child(0),
+ *node1 = node->get_child(1);
+ return node0->is_unaligned() || node1->is_unaligned();
+}
+
RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_)
{
}
-void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+void RegularBVH::pack_leaf(const BVHStackEntry& e,
+ const LeafNode *leaf)
{
float4 data[BVH_NODE_LEAF_SIZE];
memset(data, 0, sizeof(data));
@@ -401,54 +442,130 @@ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
- memcpy(&pack.leaf_nodes[e.idx * BVH_NODE_LEAF_SIZE], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
+}
+
+void RegularBVH::pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
+{
+ if (e0.node->is_unaligned() || e1.node->is_unaligned()) {
+ pack_unaligned_inner(e, e0, e1);
+ } else {
+ pack_aligned_inner(e, e0, e1);
+ }
}
-void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
+void RegularBVH::pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
{
- pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
+ pack_aligned_node(e.idx,
+ e0.node->m_bounds, e1.node->m_bounds,
+ e0.encodeIdx(), e1.encodeIdx(),
+ e0.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED,
+ e1.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED);
}
-void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
+void RegularBVH::pack_aligned_node(int idx,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1)
{
int4 data[BVH_NODE_SIZE] =
{
+ make_int4(visibility0, visibility1, c0, c1),
make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)),
make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)),
make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)),
- make_int4(c0, c1, visibility0, visibility1)
};
- memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE);
}
-void RegularBVH::pack_nodes(const BVHNode *root)
+void RegularBVH::pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
{
- size_t tot_node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
- size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- size_t node_size = tot_node_size - leaf_node_size;
+ pack_unaligned_node(e.idx,
+ e0.node->get_aligned_space(),
+ e1.node->get_aligned_space(),
+ e0.node->m_bounds,
+ e1.node->m_bounds,
+ e0.encodeIdx(), e1.encodeIdx(),
+ e0.node->m_visibility, e1.node->m_visibility);
+}
- /* resize arrays */
- pack.nodes.clear();
+void RegularBVH::pack_unaligned_node(int idx,
+ const Transform& aligned_space0,
+ const Transform& aligned_space1,
+ const BoundBox& bounds0,
+ const BoundBox& bounds1,
+ int c0, int c1,
+ uint visibility0, uint visibility1)
+{
+ float4 data[BVH_UNALIGNED_NODE_SIZE];
+ Transform space0 = BVHUnaligned::compute_node_transform(bounds0,
+ aligned_space0);
+ Transform space1 = BVHUnaligned::compute_node_transform(bounds1,
+ aligned_space1);
+ data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(c0),
+ __int_as_float(c1));
+
+ data[1] = space0.x;
+ data[2] = space0.y;
+ data[3] = space0.z;
+ data[4] = space1.x;
+ data[5] = space1.y;
+ data[6] = space1.z;
+
+ memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE);
+}
- /* for top level BVH, first merge existing BVH's so we know the offsets */
+void RegularBVH::pack_nodes(const BVHNode *root)
+{
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if(params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes =
+ root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_NODE_SIZE;
+ }
+ /* Resize arrays */
+ pack.nodes.clear();
+ pack.leaf_nodes.clear();
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
if(params.top_level) {
- pack_instances(node_size*BVH_NODE_SIZE,
- leaf_node_size*BVH_NODE_LEAF_SIZE);
+ pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE);
}
else {
- pack.nodes.resize(node_size*BVH_NODE_SIZE);
- pack.leaf_nodes.resize(leaf_node_size*BVH_NODE_LEAF_SIZE);
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE);
}
int nextNodeIdx = 0, nextLeafNodeIdx = 0;
vector<BVHStackEntry> stack;
stack.reserve(BVHParams::MAX_DEPTH*2);
- if(root->is_leaf())
+ if(root->is_leaf()) {
stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
- else
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += node_bvh_is_unaligned(root)
+ ? BVH_UNALIGNED_NODE_SIZE
+ : BVH_NODE_SIZE;
+ }
while(stack.size()) {
BVHStackEntry e = stack.back();
@@ -456,20 +573,31 @@ void RegularBVH::pack_nodes(const BVHNode *root)
if(e.node->is_leaf()) {
/* leaf node */
- const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+ const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
pack_leaf(e, leaf);
}
else {
/* innner node */
- int idx0 = (e.node->get_child(0)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
- int idx1 = (e.node->get_child(1)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
- stack.push_back(BVHStackEntry(e.node->get_child(0), idx0));
- stack.push_back(BVHStackEntry(e.node->get_child(1), idx1));
+ int idx[2];
+ for (int i = 0; i < 2; ++i) {
+ if (e.node->get_child(i)->is_leaf()) {
+ idx[i] = nextLeafNodeIdx++;
+ }
+ else {
+ idx[i] = nextNodeIdx;
+ nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i))
+ ? BVH_UNALIGNED_NODE_SIZE
+ : BVH_NODE_SIZE;
+ }
+ }
+
+ stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0]));
+ stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1]));
pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
}
}
-
+ assert(node_size == nextNodeIdx);
/* root index to start traversal at, to handle case of single leaf node */
pack.root_index = (root->is_leaf())? -1: 0;
}
@@ -486,7 +614,7 @@ void RegularBVH::refit_nodes()
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
if(leaf) {
- int4 *data = &pack.leaf_nodes[idx*BVH_NODE_LEAF_SIZE];
+ int4 *data = &pack.leaf_nodes[idx];
int c0 = data[0].x;
int c1 = data[0].y;
/* refit leaf node */
@@ -565,9 +693,9 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
sizeof(float4)*BVH_NODE_LEAF_SIZE);
}
else {
- int4 *data = &pack.nodes[idx*BVH_NODE_SIZE];
- int c0 = data[3].x;
- int c1 = data[3].y;
+ int4 *data = &pack.nodes[idx];
+ int c0 = data[0].z;
+ int c1 = data[0].w;
/* refit inner node, set bbox from children */
BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty;
uint visibility0 = 0, visibility1 = 0;
@@ -575,7 +703,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
- pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
+ pack_aligned_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
bbox.grow(bbox0);
bbox.grow(bbox1);
@@ -585,6 +713,33 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
/* QBVH */
+/* Can we avoid this somehow or make more generic?
+ *
+ * Perhaps we can merge nodes in actual tree and make our
+ * life easier all over the place.
+ */
+static bool node_qbvh_is_unaligned(const BVHNode *node)
+{
+ const BVHNode *node0 = node->get_child(0),
+ *node1 = node->get_child(1);
+ bool has_unaligned = false;
+ if(node0->is_leaf()) {
+ has_unaligned |= node0->is_unaligned();
+ }
+ else {
+ has_unaligned |= node0->get_child(0)->is_unaligned();
+ has_unaligned |= node0->get_child(1)->is_unaligned();
+ }
+ if(node1->is_leaf()) {
+ has_unaligned |= node1->is_unaligned();
+ }
+ else {
+ has_unaligned |= node1->get_child(0)->is_unaligned();
+ has_unaligned |= node1->get_child(1)->is_unaligned();
+ }
+ return has_unaligned;
+}
+
QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_)
{
@@ -610,66 +765,153 @@ void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
- memcpy(&pack.leaf_nodes[e.idx * BVH_QNODE_LEAF_SIZE], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+}
+
+void QBVH::pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
+{
+ bool has_unaligned = false;
+ /* Check whether we have to create unaligned node or all nodes are aligned
+ * and we can cut some corner here.
+ */
+ if(params.use_unaligned_nodes) {
+ for(int i = 0; i < num; i++) {
+ if(en[i].node->is_unaligned()) {
+ has_unaligned = true;
+ break;
+ }
+ }
+ }
+ if(has_unaligned) {
+ /* There's no unaligned children, pack into AABB node. */
+ pack_unaligned_inner(e, en, num);
+ }
+ else {
+ /* Create unaligned node with orientation transform for each of the
+ * children.
+ */
+ pack_aligned_inner(e, en, num);
+ }
}
-void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
+void QBVH::pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
{
float4 data[BVH_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
+ data[0].x = __uint_as_float(e.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED);
for(int i = 0; i < num; i++) {
float3 bb_min = en[i].node->m_bounds.min;
float3 bb_max = en[i].node->m_bounds.max;
- data[0][i] = bb_min.x;
- data[1][i] = bb_max.x;
- data[2][i] = bb_min.y;
- data[3][i] = bb_max.y;
- data[4][i] = bb_min.z;
- data[5][i] = bb_max.z;
+ data[1][i] = bb_min.x;
+ data[2][i] = bb_max.x;
+ data[3][i] = bb_min.y;
+ data[4][i] = bb_max.y;
+ data[5][i] = bb_min.z;
+ data[6][i] = bb_max.z;
- data[6][i] = __int_as_float(en[i].encodeIdx());
+ data[7][i] = __int_as_float(en[i].encodeIdx());
}
for(int i = num; i < 4; i++) {
/* We store BB which would never be recorded as intersection
* so kernel might safely assume there are always 4 child nodes.
*/
- data[0][i] = FLT_MAX;
- data[1][i] = -FLT_MAX;
+ data[1][i] = FLT_MAX;
+ data[2][i] = -FLT_MAX;
+
+ data[3][i] = FLT_MAX;
+ data[4][i] = -FLT_MAX;
+
+ data[5][i] = FLT_MAX;
+ data[6][i] = -FLT_MAX;
+
+ data[7][i] = __int_as_float(0);
+ }
+
+ memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_QNODE_SIZE);
+}
+
+void QBVH::pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
+{
+ float4 data[BVH_UNALIGNED_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
+
+ data[0].x = __uint_as_float(e.node->m_visibility | PATH_RAY_NODE_UNALIGNED);
+
+ for(int i = 0; i < num; i++) {
+ Transform space = BVHUnaligned::compute_node_transform(
+ en[i].node->m_bounds,
+ en[i].node->get_aligned_space());
+
+ data[1][i] = space.x.x;
+ data[2][i] = space.x.y;
+ data[3][i] = space.x.z;
+
+ data[4][i] = space.y.x;
+ data[5][i] = space.y.y;
+ data[6][i] = space.y.z;
+
+ data[7][i] = space.z.x;
+ data[8][i] = space.z.y;
+ data[9][i] = space.z.z;
- data[2][i] = FLT_MAX;
- data[3][i] = -FLT_MAX;
+ data[10][i] = space.x.w;
+ data[11][i] = space.y.w;
+ data[12][i] = space.z.w;
- data[4][i] = FLT_MAX;
- data[5][i] = -FLT_MAX;
+ data[13][i] = __int_as_float(en[i].encodeIdx());
+ }
- data[6][i] = __int_as_float(0);
+ for(int i = num; i < 4; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
+ for(int j = 1; j < 13; ++j) {
+ data[j][i] = 0.0f;
+ }
+ data[13][i] = __int_as_float(0);
}
- memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
+ memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE);
}
/* Quad SIMD Nodes */
void QBVH::pack_nodes(const BVHNode *root)
{
- size_t tot_node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
- size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- size_t node_size = tot_node_size - leaf_node_size;
-
- /* resize arrays */
+ /* Calculate size of the arrays required. */
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if(params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes =
+ root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_QNODE_SIZE;
+ }
+ /* Resize arrays. */
pack.nodes.clear();
pack.leaf_nodes.clear();
-
- /* for top level BVH, first merge existing BVH's so we know the offsets */
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
if(params.top_level) {
- pack_instances(node_size*BVH_QNODE_SIZE,
- leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
}
else {
- pack.nodes.resize(node_size*BVH_QNODE_SIZE);
- pack.leaf_nodes.resize(leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
}
int nextNodeIdx = 0, nextLeafNodeIdx = 0;
@@ -680,7 +922,10 @@ void QBVH::pack_nodes(const BVHNode *root)
stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
}
else {
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += node_qbvh_is_unaligned(root)
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_QNODE_SIZE;
}
while(stack.size()) {
@@ -689,19 +934,17 @@ void QBVH::pack_nodes(const BVHNode *root)
if(e.node->is_leaf()) {
/* leaf node */
- const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+ const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
pack_leaf(e, leaf);
}
else {
- /* inner node */
+ /* Inner node. */
const BVHNode *node = e.node;
const BVHNode *node0 = node->get_child(0);
const BVHNode *node1 = node->get_child(1);
-
- /* collect nodes */
+ /* Collect nodes. */
const BVHNode *nodes[4];
int numnodes = 0;
-
if(node0->is_leaf()) {
nodes[numnodes++] = node0;
}
@@ -709,7 +952,6 @@ void QBVH::pack_nodes(const BVHNode *root)
nodes[numnodes++] = node0->get_child(0);
nodes[numnodes++] = node0->get_child(1);
}
-
if(node1->is_leaf()) {
nodes[numnodes++] = node1;
}
@@ -717,25 +959,26 @@ void QBVH::pack_nodes(const BVHNode *root)
nodes[numnodes++] = node1->get_child(0);
nodes[numnodes++] = node1->get_child(1);
}
-
- /* push entries on the stack */
- for(int i = 0; i < numnodes; i++) {
+ /* Push entries on the stack. */
+ for(int i = 0; i < numnodes; ++i) {
int idx;
if(nodes[i]->is_leaf()) {
idx = nextLeafNodeIdx++;
}
else {
- idx = nextNodeIdx++;
+ idx = nextNodeIdx;
+ nextNodeIdx += node_qbvh_is_unaligned(nodes[i])
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_QNODE_SIZE;
}
stack.push_back(BVHStackEntry(nodes[i], idx));
}
-
- /* set node */
+ /* Set node. */
pack_inner(e, &stack[stack.size()-numnodes], numnodes);
}
}
-
- /* root index to start traversal at, to handle case of single leaf node */
+ assert(node_size == nextNodeIdx);
+ /* Root index to start traversal at, to handle case of single leaf node. */
pack.root_index = (root->is_leaf())? -1: 0;
}
@@ -751,7 +994,7 @@ void QBVH::refit_nodes()
void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
if(leaf) {
- int4 *data = &pack.leaf_nodes[idx*BVH_QNODE_LEAF_SIZE];
+ int4 *data = &pack.leaf_nodes[idx];
int4 c = data[0];
/* Refit leaf node. */
for(int prim = c.x; prim < c.y; prim++) {
@@ -833,13 +1076,18 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
leaf_data[0].y = __int_as_float(c.y);
leaf_data[0].z = __uint_as_float(visibility);
leaf_data[0].w = __uint_as_float(c.w);
- memcpy(&pack.leaf_nodes[idx * BVH_QNODE_LEAF_SIZE],
- leaf_data,
- sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
}
else {
- int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE];
- int4 c = data[6];
+ int4 *data = &pack.nodes[idx];
+ bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
+ int4 c;
+ if(is_unaligned) {
+ c = data[13];
+ }
+ else {
+ c = data[7];
+ }
/* Refit inner node, set bbox from children. */
BoundBox child_bbox[4] = {BoundBox::empty,
BoundBox::empty,
@@ -858,21 +1106,62 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
}
}
- float4 inner_data[BVH_QNODE_SIZE];
- for(int i = 0; i < 4; ++i) {
- float3 bb_min = child_bbox[i].min;
- float3 bb_max = child_bbox[i].max;
- inner_data[0][i] = bb_min.x;
- inner_data[1][i] = bb_max.x;
- inner_data[2][i] = bb_min.y;
- inner_data[3][i] = bb_max.y;
- inner_data[4][i] = bb_min.z;
- inner_data[5][i] = bb_max.z;
- inner_data[6][i] = __int_as_float(c[i]);
+ /* TODO(sergey): To be de-duplicated with pack_inner(),
+ * but for that need some sort of pack_node(). which operates with
+ * direct data, not stack element.
+ */
+ if(is_unaligned) {
+ Transform aligned_space = transform_identity();
+ float4 inner_data[BVH_UNALIGNED_QNODE_SIZE];
+ inner_data[0] = make_float4(
+ __int_as_float(visibility | PATH_RAY_NODE_UNALIGNED),
+ 0.0f,
+ 0.0f,
+ 0.0f);
+ for(int i = 0; i < 4; ++i) {
+ Transform space = BVHUnaligned::compute_node_transform(
+ child_bbox[i],
+ aligned_space);
+ inner_data[1][i] = space.x.x;
+ inner_data[2][i] = space.x.y;
+ inner_data[3][i] = space.x.z;
+
+ inner_data[4][i] = space.y.x;
+ inner_data[5][i] = space.y.y;
+ inner_data[6][i] = space.y.z;
+
+ inner_data[7][i] = space.z.x;
+ inner_data[8][i] = space.z.y;
+ inner_data[9][i] = space.z.z;
+
+ inner_data[10][i] = space.x.w;
+ inner_data[11][i] = space.y.w;
+ inner_data[12][i] = space.z.w;
+
+ inner_data[13][i] = __int_as_float(c[i]);
+ }
+ memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE);
+ }
+ else {
+ float4 inner_data[BVH_QNODE_SIZE];
+ inner_data[0] = make_float4(
+ __int_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED),
+ 0.0f,
+ 0.0f,
+ 0.0f);
+ for(int i = 0; i < 4; ++i) {
+ float3 bb_min = child_bbox[i].min;
+ float3 bb_max = child_bbox[i].max;
+ inner_data[1][i] = bb_min.x;
+ inner_data[2][i] = bb_max.x;
+ inner_data[3][i] = bb_min.y;
+ inner_data[4][i] = bb_max.y;
+ inner_data[5][i] = bb_min.z;
+ inner_data[6][i] = bb_max.z;
+ inner_data[7][i] = __int_as_float(c[i]);
+ }
+ memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_QNODE_SIZE);
}
- memcpy(&pack.nodes[idx * BVH_QNODE_SIZE],
- inner_data,
- sizeof(float4)*BVH_QNODE_SIZE);
}
}
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 6076c25ca31..16752076f6a 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -35,11 +35,14 @@ class Progress;
#define BVH_NODE_SIZE 4
#define BVH_NODE_LEAF_SIZE 1
-#define BVH_QNODE_SIZE 7
+#define BVH_QNODE_SIZE 8
#define BVH_QNODE_LEAF_SIZE 1
#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
+#define BVH_UNALIGNED_NODE_SIZE 7
+#define BVH_UNALIGNED_QNODE_SIZE 14
+
/* Packed BVH
*
* BVH stored as it will be used for traversal on the rendering device. */
@@ -52,8 +55,10 @@ struct PackedBVH {
array<int4> leaf_nodes;
/* object index to BVH node index mapping for instances */
array<int> object_node;
- /* Aligned triangle storage for fatser lookup in the kernel. */
- array<float4> tri_storage;
+ /* Mapping from primitive index to index in triangle array. */
+ array<uint> prim_tri_index;
+ /* Continuous storage of triangle vertices. */
+ array<float4> prim_tri_verts;
/* primitive type - triangle or strand */
array<int> prim_type;
/* visibility visibilitys for primitives */
@@ -91,7 +96,7 @@ public:
protected:
BVH(const BVHParams& params, const vector<Object*>& objects);
- /* triangles and strands*/
+ /* triangles and strands */
void pack_primitives();
void pack_triangle(int idx, float4 storage[3]);
@@ -115,9 +120,32 @@ protected:
/* pack */
void pack_nodes(const BVHNode *root);
- void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
- void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
- void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1);
+
+ void pack_leaf(const BVHStackEntry& e,
+ const LeafNode *leaf);
+ void pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+
+ void pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+ void pack_aligned_node(int idx,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1);
+
+ void pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+ void pack_unaligned_node(int idx,
+ const Transform& aligned_space0,
+ const Transform& aligned_space1,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1);
/* refit */
void refit_nodes();
@@ -136,9 +164,17 @@ protected:
/* pack */
void pack_nodes(const BVHNode *root);
+
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
+ void pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num);
+ void pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num);
+
/* refit */
void refit_nodes();
void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
index b07e870d759..5ddd7349f7b 100644
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ b/intern/cycles/bvh/bvh_binning.cpp
@@ -52,12 +52,35 @@ __forceinline int get_best_dimension(const float4& bestSAH)
/* BVH Object Binning */
-BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
-: BVHRange(job), splitSAH(FLT_MAX), dim(0), pos(0)
+BVHObjectBinning::BVHObjectBinning(const BVHRange& job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+: BVHRange(job),
+ splitSAH(FLT_MAX),
+ dim(0),
+ pos(0),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
+ if(aligned_space_ == NULL) {
+ bounds_ = bounds();
+ cent_bounds_ = cent_bounds();
+ }
+ else {
+ /* TODO(sergey): With some additional storage we can avoid
+ * need in re-calculating this.
+ */
+ bounds_ = unaligned_heuristic->compute_aligned_boundbox(
+ *this,
+ prims,
+ *aligned_space,
+ &cent_bounds_);
+ }
+
/* compute number of bins to use and precompute scaling factor for binning */
num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f*size()));
- scale = rcp(cent_bounds().size()) * make_float3((float)num_bins);
+ scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
/* initialize binning counter and bounds */
BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
@@ -79,30 +102,34 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
const BVHReference& prim0 = prims[start() + i + 0];
const BVHReference& prim1 = prims[start() + i + 1];
- int4 bin0 = get_bin(prim0.bounds());
- int4 bin1 = get_bin(prim1.bounds());
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ BoundBox bounds1 = get_prim_bounds(prim1);
+
+ int4 bin0 = get_bin(bounds0);
+ int4 bin1 = get_bin(bounds1);
/* increase bounds for bins for even primitive */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds());
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds());
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds());
+ int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
/* increase bounds of bins for odd primitive */
- int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(prim1.bounds());
- int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(prim1.bounds());
- int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(prim1.bounds());
+ int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(bounds1);
+ int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(bounds1);
+ int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(bounds1);
}
/* for uneven number of primitives */
if(i < ssize_t(size())) {
/* map primitive to bin */
const BVHReference& prim0 = prims[start() + i];
- int4 bin0 = get_bin(prim0.bounds());
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ int4 bin0 = get_bin(bounds0);
/* increase bounds of bins */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds());
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds());
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds());
+ int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
}
}
@@ -151,17 +178,19 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
bestSAH = min(sah,bestSAH);
}
- int4 mask = float3_to_float4(cent_bounds().size()) <= make_float4(0.0f);
+ int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
/* find best dimension */
dim = get_best_dimension(bestSAH);
splitSAH = bestSAH[dim];
pos = bestSplit[dim];
- leafSAH = bounds().half_area() * blocks(size());
+ leafSAH = bounds_.half_area() * blocks(size());
}
-void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const
+void BVHObjectBinning::split(BVHReference* prims,
+ BVHObjectBinning& left_o,
+ BVHObjectBinning& right_o) const
{
size_t N = size();
@@ -176,10 +205,12 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO
prefetch_L2(&prims[start() + l + 8]);
prefetch_L2(&prims[start() + r - 8]);
- const BVHReference& prim = prims[start() + l];
+ BVHReference prim = prims[start() + l];
+ BoundBox unaligned_bounds = get_prim_bounds(prim);
+ float3 unaligned_center = unaligned_bounds.center2();
float3 center = prim.bounds().center2();
- if(get_bin(center)[dim] < pos) {
+ if(get_bin(unaligned_center)[dim] < pos) {
lgeom_bounds.grow(prim.bounds());
lcent_bounds.grow(center);
l++;
@@ -191,7 +222,6 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO
r--;
}
}
-
/* finish */
if(l != 0 && N-1-r != 0) {
right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N-1-r), prims);
diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h
index 60742157055..52955f70151 100644
--- a/intern/cycles/bvh/bvh_binning.h
+++ b/intern/cycles/bvh/bvh_binning.h
@@ -19,11 +19,14 @@
#define __BVH_BINNING_H__
#include "bvh_params.h"
+#include "bvh_unaligned.h"
#include "util_types.h"
CCL_NAMESPACE_BEGIN
+class BVHBuild;
+
/* Single threaded object binner. Finds the split with the best SAH heuristic
* by testing for each dimension multiple partitionings for regular spaced
* partition locations. A partitioning for a partition location is computed,
@@ -34,10 +37,18 @@ CCL_NAMESPACE_BEGIN
class BVHObjectBinning : public BVHRange
{
public:
- __forceinline BVHObjectBinning() {}
- BVHObjectBinning(const BVHRange& job, BVHReference *prims);
+ __forceinline BVHObjectBinning() : leafSAH(FLT_MAX) {}
+
+ BVHObjectBinning(const BVHRange& job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
- void split(BVHReference *prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const;
+ void split(BVHReference *prims,
+ BVHObjectBinning& left_o,
+ BVHObjectBinning& right_o) const;
+
+ __forceinline const BoundBox& unaligned_bounds() { return bounds_; }
float splitSAH; /* SAH cost of the best split */
float leafSAH; /* SAH cost of creating a leaf */
@@ -48,13 +59,20 @@ protected:
size_t num_bins; /* actual number of bins to use */
float3 scale; /* scaling factor to compute bin */
+ /* Effective bounds and centroid bounds. */
+ BoundBox bounds_;
+ BoundBox cent_bounds_;
+
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
enum { MAX_BINS = 32 };
enum { LOG_BLOCK_SIZE = 2 };
/* computes the bin numbers for each dimension for a box. */
__forceinline int4 get_bin(const BoundBox& box) const
{
- int4 a = make_int4((box.center2() - cent_bounds().min)*scale - make_float3(0.5f));
+ int4 a = make_int4((box.center2() - cent_bounds_.min)*scale - make_float3(0.5f));
int4 mn = make_int4(0);
int4 mx = make_int4((int)num_bins-1);
@@ -64,7 +82,7 @@ protected:
/* computes the bin numbers for each dimension for a point. */
__forceinline int4 get_bin(const float3& c) const
{
- return make_int4((c - cent_bounds().min)*scale - make_float3(0.5f));
+ return make_int4((c - cent_bounds_.min)*scale - make_float3(0.5f));
}
/* compute the number of blocks occupied for each dimension. */
@@ -78,6 +96,17 @@ protected:
{
return (int)((a+((1LL << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE);
}
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 3f687224eee..67ffb6853d6 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -33,6 +33,7 @@
#include "util_stack_allocator.h"
#include "util_simd.h"
#include "util_time.h"
+#include "util_queue.h"
CCL_NAMESPACE_BEGIN
@@ -99,7 +100,8 @@ BVHBuild::BVHBuild(const vector<Object*>& objects_,
prim_object(prim_object_),
params(params_),
progress(progress_),
- progress_start_time(0.0)
+ progress_start_time(0.0),
+ unaligned_heuristic(objects_)
{
spatial_min_overlap = 0.0f;
}
@@ -112,70 +114,74 @@ BVHBuild::~BVHBuild()
void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
{
- Attribute *attr_mP = NULL;
-
- if(mesh->has_motion_blur())
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ Attribute *attr_mP = NULL;
- size_t num_triangles = mesh->num_triangles();
- for(uint j = 0; j < num_triangles; j++) {
- Mesh::Triangle t = mesh->get_triangle(j);
- BoundBox bounds = BoundBox::empty;
- PrimitiveType type = PRIMITIVE_TRIANGLE;
+ if(mesh->has_motion_blur())
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ size_t num_triangles = mesh->num_triangles();
+ for(uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ BoundBox bounds = BoundBox::empty;
+ PrimitiveType type = PRIMITIVE_TRIANGLE;
- t.bounds_grow(&mesh->verts[0], bounds);
+ t.bounds_grow(&mesh->verts[0], bounds);
- /* motion triangles */
- if(attr_mP) {
- size_t mesh_size = mesh->verts.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *vert_steps = attr_mP->data_float3();
+ /* motion triangles */
+ if(attr_mP) {
+ size_t mesh_size = mesh->verts.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *vert_steps = attr_mP->data_float3();
- for(size_t i = 0; i < steps; i++)
- t.bounds_grow(vert_steps + i*mesh_size, bounds);
+ for(size_t i = 0; i < steps; i++)
+ t.bounds_grow(vert_steps + i*mesh_size, bounds);
- type = PRIMITIVE_MOTION_TRIANGLE;
- }
+ type = PRIMITIVE_MOTION_TRIANGLE;
+ }
- if(bounds.valid()) {
- references.push_back(BVHReference(bounds, j, i, type));
- root.grow(bounds);
- center.grow(bounds.center2());
+ if(bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
}
}
- Attribute *curve_attr_mP = NULL;
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ Attribute *curve_attr_mP = NULL;
- if(mesh->has_motion_blur())
- curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if(mesh->has_motion_blur())
+ curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- size_t num_curves = mesh->num_curves();
- for(uint j = 0; j < num_curves; j++) {
- Mesh::Curve curve = mesh->get_curve(j);
- PrimitiveType type = PRIMITIVE_CURVE;
+ size_t num_curves = mesh->num_curves();
+ for(uint j = 0; j < num_curves; j++) {
+ Mesh::Curve curve = mesh->get_curve(j);
+ PrimitiveType type = PRIMITIVE_CURVE;
- for(int k = 0; k < curve.num_keys - 1; k++) {
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds);
+ for(int k = 0; k < curve.num_keys - 1; k++) {
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds);
- /* motion curve */
- if(curve_attr_mP) {
- size_t mesh_size = mesh->curve_keys.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *key_steps = curve_attr_mP->data_float3();
+ /* motion curve */
+ if(curve_attr_mP) {
+ size_t mesh_size = mesh->curve_keys.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *key_steps = curve_attr_mP->data_float3();
- for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds);
+ for(size_t i = 0; i < steps; i++)
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds);
- type = PRIMITIVE_MOTION_CURVE;
- }
+ type = PRIMITIVE_MOTION_CURVE;
+ }
- if(bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
-
- references.push_back(BVHReference(bounds, j, i, packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
+ if(bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
+
+ references.push_back(BVHReference(bounds, j, i, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
}
}
}
@@ -209,15 +215,23 @@ void BVHBuild::add_references(BVHRange& root)
continue;
}
if(!ob->mesh->is_instanced()) {
- num_alloc_references += ob->mesh->num_triangles();
- num_alloc_references += count_curve_segments(ob->mesh);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
}
else
num_alloc_references++;
}
else {
- num_alloc_references += ob->mesh->num_triangles();
- num_alloc_references += count_curve_segments(ob->mesh);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
}
}
@@ -340,6 +354,8 @@ BVHNode* BVHBuild::run()
<< string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n"
<< " Number of leaf nodes: "
<< string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT)) << "\n"
<< " Allocation slop factor: "
<< ((prim_type.capacity() != 0)
? (float)prim_type.size() / prim_type.capacity()
@@ -445,10 +461,11 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
float leafSAH = params.sah_primitive_cost * range.leafSAH;
float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH;
- /* have at least one inner node on top level, for performance and correct
- * visibility tests, since object instances do not check visibility flag */
+ /* Have at least one inner node on top level, for performance and correct
+ * visibility tests, since object instances do not check visibility flag.
+ */
if(!(range.size() > 0 && params.top_level && level == 0)) {
- /* make leaf node when threshold reached or SAH tells us */
+ /* Make leaf node when threshold reached or SAH tells us. */
if((params.small_enough_for_leaf(size, level)) ||
(range_within_max_leaf_size(range, references) && leafSAH < splitSAH))
{
@@ -456,28 +473,70 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
}
}
- /* perform split */
+ BVHObjectBinning unaligned_range;
+ float unalignedSplitSAH = FLT_MAX;
+ float unalignedLeafSAH = FLT_MAX;
+ Transform aligned_space;
+ if(params.use_unaligned_nodes &&
+ splitSAH > params.unaligned_split_threshold*leafSAH)
+ {
+ aligned_space = unaligned_heuristic.compute_aligned_space(
+ range, &references[0]);
+ unaligned_range = BVHObjectBinning(range,
+ &references[0],
+ &unaligned_heuristic,
+ &aligned_space);
+ unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
+ params.sah_primitive_cost * unaligned_range.splitSAH;
+ unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
+ if(!(range.size() > 0 && params.top_level && level == 0)) {
+ if(unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
+ range_within_max_leaf_size(range, references))
+ {
+ return create_leaf_node(range, references);
+ }
+ }
+ }
+
+ /* Perform split. */
BVHObjectBinning left, right;
- range.split(&references[0], left, right);
+ if(unalignedSplitSAH < splitSAH) {
+ unaligned_range.split(&references[0], left, right);
+ }
+ else {
+ range.split(&references[0], left, right);
+ }
- /* create inner node. */
- InnerNode *inner;
+ BoundBox bounds;
+ if(unalignedSplitSAH < splitSAH) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(
+ range, &references[0], aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+ /* Create inner node. */
+ InnerNode *inner;
if(range.size() < THREAD_TASK_SIZE) {
/* local build */
BVHNode *leftnode = build_node(left, level + 1);
BVHNode *rightnode = build_node(right, level + 1);
- inner = new InnerNode(range.bounds(), leftnode, rightnode);
+ inner = new InnerNode(bounds, leftnode, rightnode);
}
else {
- /* threaded build */
- inner = new InnerNode(range.bounds());
+ /* Threaded build */
+ inner = new InnerNode(bounds);
task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true);
task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true);
}
+ if(unalignedSplitSAH < splitSAH) {
+ inner->set_aligned_space(aligned_space);
+ }
+
return inner;
}
@@ -516,16 +575,54 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
return create_leaf_node(range, *references);
}
}
+ float leafSAH = params.sah_primitive_cost * split.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * split.nodeSAH;
+
+ BVHMixedSplit unaligned_split;
+ float unalignedSplitSAH = FLT_MAX;
+ /* float unalignedLeafSAH = FLT_MAX; */
+ Transform aligned_space;
+ if(params.use_unaligned_nodes &&
+ splitSAH > params.unaligned_split_threshold*leafSAH)
+ {
+ aligned_space =
+ unaligned_heuristic.compute_aligned_space(range, &references->at(0));
+ unaligned_split = BVHMixedSplit(this,
+ storage,
+ range,
+ references,
+ level,
+ &unaligned_heuristic,
+ &aligned_space);
+ /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
+ unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
+ params.sah_primitive_cost * unaligned_split.nodeSAH;
+ /* TOOD(sergey): Check we can create leaf already. */
+ }
/* Do split. */
BVHRange left, right;
- split.split(this, left, right, range);
+ if(unalignedSplitSAH < splitSAH) {
+ unaligned_split.split(this, left, right, range);
+ }
+ else {
+ split.split(this, left, right, range);
+ }
progress_total += left.size() + right.size() - range.size();
+ BoundBox bounds;
+ if(unalignedSplitSAH < splitSAH) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(
+ range, &references->at(0), aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
/* Create inner node. */
InnerNode *inner;
-
if(range.size() < THREAD_TASK_SIZE) {
/* Local build. */
@@ -539,11 +636,11 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
/* Build right node. */
BVHNode *rightnode = build_node(right, &copy, level + 1, thread_id);
- inner = new InnerNode(range.bounds(), leftnode, rightnode);
+ inner = new InnerNode(bounds, leftnode, rightnode);
}
else {
/* Threaded build. */
- inner = new InnerNode(range.bounds());
+ inner = new InnerNode(bounds);
task_pool.push(new BVHSpatialSplitBuildTask(this,
inner,
0,
@@ -560,6 +657,10 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
true);
}
+ if(unalignedSplitSAH < splitSAH) {
+ inner->set_aligned_space(aligned_space);
+ }
+
return inner;
}
@@ -616,6 +717,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
+ vector<BVHReference, LeafStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
/* TODO(sergey): In theory we should be able to store references. */
typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
@@ -634,6 +736,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
const BVHReference& ref = references[range.start() + i];
if(ref.prim_index() != -1) {
int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL);
+ p_ref[type_index].push_back(ref);
p_type[type_index].push_back(ref.prim_type());
p_index[type_index].push_back(ref.prim_index());
p_object[type_index].push_back(ref.prim_object());
@@ -674,16 +777,38 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
if(num != 0) {
assert(p_type[i].size() == p_index[i].size());
assert(p_type[i].size() == p_object[i].size());
+ Transform aligned_space;
+ bool alignment_found = false;
for(int j = 0; j < num; ++j) {
const int index = start_index + j;
local_prim_type[index] = p_type[i][j];
local_prim_index[index] = p_index[i][j];
local_prim_object[index] = p_object[i][j];
+ if(params.use_unaligned_nodes && !alignment_found) {
+ alignment_found =
+ unaligned_heuristic.compute_aligned_space(p_ref[i][j],
+ &aligned_space);
+ }
+ }
+ LeafNode *leaf_node = new LeafNode(bounds[i],
+ visibility[i],
+ start_index,
+ start_index + num);
+ if(alignment_found) {
+ /* Need to recalculate leaf bounds with new alignment. */
+ leaf_node->m_bounds = BoundBox::empty;
+ for(int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ BoundBox ref_bounds =
+ unaligned_heuristic.compute_aligned_prim_boundbox(
+ ref,
+ aligned_space);
+ leaf_node->m_bounds.grow(ref_bounds);
+ }
+ /* Set alignment space. */
+ leaf_node->set_aligned_space(aligned_space);
}
- leaves[num_leaves++] = new LeafNode(bounds[i],
- visibility[i],
- start_index,
- start_index + num);
+ leaves[num_leaves++] = leaf_node;
start_index += num;
}
}
@@ -765,6 +890,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
++num_leaves;
}
+ /* TODO(sergey): Need to take care of alignment when number of leaves
+ * is more than 1.
+ */
if(num_leaves == 1) {
/* Simplest case: single leaf, just return it.
* In all the rest cases we'll be creating intermediate inner node with
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index a015b89d72f..64180349935 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -22,6 +22,7 @@
#include "bvh.h"
#include "bvh_binning.h"
+#include "bvh_unaligned.h"
#include "util_boundbox.h"
#include "util_task.h"
@@ -59,13 +60,14 @@ protected:
friend class BVHSpatialSplit;
friend class BVHBuildTask;
friend class BVHSpatialSplitBuildTask;
+ friend class BVHObjectBinning;
- /* adding references */
+ /* Adding references. */
void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i);
void add_references(BVHRange& root);
- /* building */
+ /* Building. */
BVHNode *build_node(const BVHRange& range,
vector<BVHReference> *references,
int level,
@@ -78,7 +80,7 @@ protected:
bool range_within_max_leaf_size(const BVHRange& range,
const vector<BVHReference>& references) const;
- /* threads */
+ /* Threads. */
enum { THREAD_TASK_SIZE = 4096 };
void thread_build_node(InnerNode *node,
int child,
@@ -92,41 +94,44 @@ protected:
int thread_id);
thread_mutex build_mutex;
- /* progress */
+ /* Progress. */
void progress_update();
- /* tree rotations */
+ /* Tree rotations. */
void rotate(BVHNode *node, int max_depth);
void rotate(BVHNode *node, int max_depth, int iterations);
- /* objects and primitive references */
+ /* Objects and primitive references. */
vector<Object*> objects;
vector<BVHReference> references;
int num_original_references;
- /* output primitive indexes and objects */
+ /* Output primitive indexes and objects. */
array<int>& prim_type;
array<int>& prim_index;
array<int>& prim_object;
- /* build parameters */
+ /* Build parameters. */
BVHParams params;
- /* progress reporting */
+ /* Progress reporting. */
Progress& progress;
double progress_start_time;
size_t progress_count;
size_t progress_total;
size_t progress_original_total;
- /* spatial splitting */
+ /* Spatial splitting. */
float spatial_min_overlap;
vector<BVHSpatialStorage> spatial_storage;
size_t spatial_free_index;
thread_spin_lock spatial_spin_lock;
- /* threads */
+ /* Threads. */
TaskPool task_pool;
+
+ /* Unaligned building. */
+ BVHUnaligned unaligned_heuristic;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
index 8294690da7d..f5cd699bdf4 100644
--- a/intern/cycles/bvh/bvh_node.cpp
+++ b/intern/cycles/bvh/bvh_node.cpp
@@ -61,6 +61,76 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const
}
}
return cnt;
+ case BVH_STAT_ALIGNED_COUNT:
+ if(!is_unaligned()) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_COUNT:
+ if(is_unaligned()) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_COUNT:
+ if(!is_leaf()) {
+ bool has_unaligned = false;
+ for(int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned();
+ }
+ cnt += has_unaligned? 0: 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_INNER_COUNT:
+ if(!is_leaf()) {
+ bool has_unaligned = false;
+ for(int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned();
+ }
+ cnt += has_unaligned? 1: 0;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_QNODE_COUNT:
+ {
+ bool has_unaligned = false;
+ for(int i = 0; i < num_children(); i++) {
+ BVHNode *node = get_child(i);
+ if(node->is_leaf()) {
+ has_unaligned |= node->is_unaligned();
+ }
+ else {
+ for(int j = 0; j < node->num_children(); j++) {
+ cnt += node->get_child(j)->getSubtreeSize(stat);
+ has_unaligned |= node->get_child(j)->is_unaligned();
+ }
+ }
+ }
+ cnt += has_unaligned? 0: 1;
+ }
+ return cnt;
+ case BVH_STAT_UNALIGNED_INNER_QNODE_COUNT:
+ {
+ bool has_unaligned = false;
+ for(int i = 0; i < num_children(); i++) {
+ BVHNode *node = get_child(i);
+ if(node->is_leaf()) {
+ has_unaligned |= node->is_unaligned();
+ }
+ else {
+ for(int j = 0; j < node->num_children(); j++) {
+ cnt += node->get_child(j)->getSubtreeSize(stat);
+ has_unaligned |= node->get_child(j)->is_unaligned();
+ }
+ }
+ }
+ cnt += has_unaligned? 1: 0;
+ }
+ return cnt;
+ case BVH_STAT_ALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && !is_unaligned()) ? 1 : 0;
+ break;
+ case BVH_STAT_UNALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && is_unaligned()) ? 1 : 0;
+ break;
default:
assert(0); /* unknown mode */
}
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
index d476fb917ed..f2965a785e6 100644
--- a/intern/cycles/bvh/bvh_node.h
+++ b/intern/cycles/bvh/bvh_node.h
@@ -31,6 +31,14 @@ enum BVH_STAT {
BVH_STAT_TRIANGLE_COUNT,
BVH_STAT_CHILDNODE_COUNT,
BVH_STAT_QNODE_COUNT,
+ BVH_STAT_ALIGNED_COUNT,
+ BVH_STAT_UNALIGNED_COUNT,
+ BVH_STAT_ALIGNED_INNER_COUNT,
+ BVH_STAT_UNALIGNED_INNER_COUNT,
+ BVH_STAT_ALIGNED_INNER_QNODE_COUNT,
+ BVH_STAT_UNALIGNED_INNER_QNODE_COUNT,
+ BVH_STAT_ALIGNED_LEAF_COUNT,
+ BVH_STAT_UNALIGNED_LEAF_COUNT,
};
class BVHParams;
@@ -38,16 +46,41 @@ class BVHParams;
class BVHNode
{
public:
- BVHNode()
+ BVHNode() : m_is_unaligned(false),
+ m_aligned_space(NULL)
{
}
- virtual ~BVHNode() {}
+ virtual ~BVHNode()
+ {
+ delete m_aligned_space;
+ }
+
virtual bool is_leaf() const = 0;
virtual int num_children() const = 0;
virtual BVHNode *get_child(int i) const = 0;
virtual int num_triangles() const { return 0; }
virtual void print(int depth = 0) const = 0;
+ bool is_unaligned() const { return m_is_unaligned; }
+
+ inline void set_aligned_space(const Transform& aligned_space)
+ {
+ m_is_unaligned = true;
+ if (m_aligned_space == NULL) {
+ m_aligned_space = new Transform(aligned_space);
+ }
+ else {
+ *m_aligned_space = aligned_space;
+ }
+ }
+
+ inline Transform get_aligned_space() const
+ {
+ if(m_aligned_space == NULL) {
+ return transform_identity();
+ }
+ return *m_aligned_space;
+ }
BoundBox m_bounds;
uint m_visibility;
@@ -58,12 +91,20 @@ public:
void deleteSubtree();
uint update_visibility();
+
+ bool m_is_unaligned;
+
+ // TODO(sergey): Can be stored as 3x3 matrix, but better to have some
+ // utilities and type defines in util_transform first.
+ Transform *m_aligned_space;
};
class InnerNode : public BVHNode
{
public:
- InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
+ InnerNode(const BoundBox& bounds,
+ BVHNode* child0,
+ BVHNode* child1)
{
m_bounds = bounds;
children[0] = child0;
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index cf683df1b31..2e698a80742 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -20,6 +20,8 @@
#include "util_boundbox.h"
+#include "kernel_types.h"
+
CCL_NAMESPACE_BEGIN
/* BVH Parameters */
@@ -31,6 +33,9 @@ public:
bool use_spatial_split;
float spatial_split_alpha;
+ /* Unaligned nodes creation threshold */
+ float unaligned_split_threshold;
+
/* SAH costs */
float sah_node_cost;
float sah_primitive_cost;
@@ -46,6 +51,14 @@ public:
/* QBVH */
bool use_qbvh;
+ /* Mask of primitives to be included into the BVH. */
+ int primitive_mask;
+
+ /* Use unaligned bounding boxes.
+ * Only used for curves BVH.
+ */
+ bool use_unaligned_nodes;
+
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@@ -58,6 +71,8 @@ public:
use_spatial_split = true;
spatial_split_alpha = 1e-5f;
+ unaligned_split_threshold = 0.7f;
+
/* todo: see if splitting up primitive cost to be separate for triangles
* and curves can help. so far in tests it doesn't help, but why? */
sah_node_cost = 1.0f;
@@ -69,6 +84,9 @@ public:
top_level = false;
use_qbvh = false;
+ use_unaligned_nodes = false;
+
+ primitive_mask = PRIMITIVE_ALL;
}
/* SAH costs */
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
index e9032c61c3b..e5bcf9995bf 100644
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ b/intern/cycles/bvh/bvh_sort.cpp
@@ -26,23 +26,27 @@ CCL_NAMESPACE_BEGIN
static const int BVH_SORT_THRESHOLD = 4096;
-/* Silly workaround for float extended precision that happens when compiling
- * on x86, due to one float staying in 80 bit precision register and the other
- * not, which causes the strictly weak ordering to break.
- */
-#if !defined(__i386__)
-# define NO_EXTENDED_PRECISION
-#else
-# define NO_EXTENDED_PRECISION volatile
-#endif
-
struct BVHReferenceCompare {
public:
int dim;
+ const BVHUnaligned *unaligned_heuristic;
+ const Transform *aligned_space;
+
+ BVHReferenceCompare(int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : dim(dim),
+ unaligned_heuristic(unaligned_heuristic),
+ aligned_space(aligned_space)
+ {
+ }
- explicit BVHReferenceCompare(int dim_)
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
{
- dim = dim_;
+ return (aligned_space != NULL)
+ ? unaligned_heuristic->compute_aligned_prim_boundbox(
+ prim, *aligned_space)
+ : prim.bounds();
}
/* Compare two references.
@@ -52,8 +56,10 @@ public:
__forceinline int compare(const BVHReference& ra,
const BVHReference& rb) const
{
- NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim];
- NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim];
+ BoundBox ra_bounds = get_prim_bounds(ra),
+ rb_bounds = get_prim_bounds(rb);
+ float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
+ float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
if(ca < cb) return -1;
else if(ca > cb) return 1;
@@ -171,10 +177,15 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool,
}
}
-void bvh_reference_sort(int start, int end, BVHReference *data, int dim)
+void bvh_reference_sort(int start,
+ int end,
+ BVHReference *data,
+ int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
{
const int count = end - start;
- BVHReferenceCompare compare(dim);
+ BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
if(count < BVH_SORT_THRESHOLD) {
/* It is important to not use any mutex if array is small enough,
* otherwise we end up in situation when we're going to sleep far
diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h
index 18aafb5f1ff..b49ca02eb60 100644
--- a/intern/cycles/bvh/bvh_sort.h
+++ b/intern/cycles/bvh/bvh_sort.h
@@ -20,7 +20,15 @@
CCL_NAMESPACE_BEGIN
-void bvh_reference_sort(int start, int end, BVHReference *data, int dim);
+class BVHUnaligned;
+struct Transform;
+
+void bvh_reference_sort(int start,
+ int end,
+ BVHReference *data,
+ int dim,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index bf68b41021f..d0d5fbe5a7a 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -32,14 +32,18 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH)
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
: sah(FLT_MAX),
dim(0),
num_left(0),
left_bounds(BoundBox::empty),
right_bounds(BoundBox::empty),
storage_(storage),
- references_(references)
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
const BVHReference *ref_ptr = &references_->at(range.start());
float min_sah = FLT_MAX;
@@ -51,12 +55,15 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
bvh_reference_sort(range.start(),
range.end(),
&references_->at(0),
- dim);
+ dim,
+ unaligned_heuristic_,
+ aligned_space_);
/* sweep right to left and determine bounds. */
BoundBox right_bounds = BoundBox::empty;
for(int i = range.size() - 1; i > 0; i--) {
- right_bounds.grow(ref_ptr[i].bounds());
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
+ right_bounds.grow(prim_bounds);
storage_->right_bounds[i - 1] = right_bounds;
}
@@ -64,7 +71,8 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BoundBox left_bounds = BoundBox::empty;
for(int i = 1; i < range.size(); i++) {
- left_bounds.grow(ref_ptr[i - 1].bounds());
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
+ left_bounds.grow(prim_bounds);
right_bounds = storage_->right_bounds[i - 1];
float sah = nodeSAH +
@@ -88,16 +96,37 @@ void BVHObjectSplit::split(BVHRange& left,
BVHRange& right,
const BVHRange& range)
{
+ assert(references_->size() > 0);
/* sort references according to split */
bvh_reference_sort(range.start(),
range.end(),
&references_->at(0),
- this->dim);
+ this->dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ BoundBox effective_left_bounds, effective_right_bounds;
+ const int num_right = range.size() - this->num_left;
+ if(aligned_space_ == NULL) {
+ effective_left_bounds = left_bounds;
+ effective_right_bounds = right_bounds;
+ }
+ else {
+ effective_left_bounds = BoundBox::empty;
+ effective_right_bounds = BoundBox::empty;
+ for(int i = 0; i < this->num_left; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
+ effective_left_bounds.grow(prim_boundbox);
+ }
+ for(int i = 0; i < num_right; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
+ effective_right_bounds.grow(prim_boundbox);
+ }
+ }
/* split node ranges */
- left = BVHRange(this->left_bounds, range.start(), this->num_left);
- right = BVHRange(this->right_bounds, left.end(), range.size() - this->num_left);
-
+ left = BVHRange(effective_left_bounds, range.start(), this->num_left);
+ right = BVHRange(effective_right_bounds, left.end(), num_right);
}
/* Spatial Split */
@@ -106,16 +135,31 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH)
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
: sah(FLT_MAX),
dim(0),
pos(0.0f),
storage_(storage),
- references_(references)
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
/* initialize bins. */
- float3 origin = range.bounds().min;
- float3 binSize = (range.bounds().max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
+ BoundBox range_bounds;
+ if(aligned_space == NULL) {
+ range_bounds = range.bounds();
+ }
+ else {
+ range_bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range,
+ &references->at(0),
+ *aligned_space);
+ }
+
+ float3 origin = range_bounds.min;
+ float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
float3 invBinSize = 1.0f / binSize;
for(int dim = 0; dim < 3; dim++) {
@@ -131,8 +175,9 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
/* chop references into bins. */
for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
const BVHReference& ref = references_->at(refIdx);
- float3 firstBinf = (ref.bounds().min - origin) * invBinSize;
- float3 lastBinf = (ref.bounds().max - origin) * invBinSize;
+ BoundBox prim_bounds = get_prim_bounds(ref);
+ float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
+ float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
@@ -140,7 +185,10 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
for(int dim = 0; dim < 3; dim++) {
- BVHReference currRef = ref;
+ BVHReference currRef(get_prim_bounds(ref),
+ ref.prim_index(),
+ ref.prim_object(),
+ ref.prim_type());
for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
BVHReference leftRef, rightRef;
@@ -209,14 +257,15 @@ void BVHSpatialSplit::split(BVHBuild *builder,
BoundBox right_bounds = BoundBox::empty;
for(int i = left_end; i < right_start; i++) {
- if(refs[i].bounds().max[this->dim] <= this->pos) {
+ BoundBox prim_bounds = get_prim_bounds(refs[i]);
+ if(prim_bounds.max[this->dim] <= this->pos) {
/* entirely on the left-hand side */
- left_bounds.grow(refs[i].bounds());
+ left_bounds.grow(prim_bounds);
swap(refs[i], refs[left_end++]);
}
- else if(refs[i].bounds().min[this->dim] >= this->pos) {
+ else if(prim_bounds.min[this->dim] >= this->pos) {
/* entirely on the right-hand side */
- right_bounds.grow(refs[i].bounds());
+ right_bounds.grow(prim_bounds);
swap(refs[i--], refs[--right_start]);
}
}
@@ -231,8 +280,12 @@ void BVHSpatialSplit::split(BVHBuild *builder,
new_refs.reserve(right_start - left_end);
while(left_end < right_start) {
/* split reference. */
+ BVHReference curr_ref(get_prim_bounds(refs[left_end]),
+ refs[left_end].prim_index(),
+ refs[left_end].prim_object(),
+ refs[left_end].prim_type());
BVHReference lref, rref;
- split_reference(*builder, lref, rref, refs[left_end], this->dim, this->pos);
+ split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
/* compute SAH for duplicate/unsplit candidates. */
BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
@@ -240,8 +293,8 @@ void BVHSpatialSplit::split(BVHBuild *builder,
BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
- lub.grow(refs[left_end].bounds());
- rub.grow(refs[left_end].bounds());
+ lub.grow(curr_ref.bounds());
+ rub.grow(curr_ref.bounds());
ldb.grow(lref.bounds());
rdb.grow(rref.bounds());
@@ -280,6 +333,17 @@ void BVHSpatialSplit::split(BVHBuild *builder,
new_refs.begin(),
new_refs.end());
}
+ if(aligned_space_ != NULL) {
+ left_bounds = right_bounds = BoundBox::empty;
+ for(int i = left_start; i < left_end - left_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ left_bounds.grow(prim_boundbox);
+ }
+ for(int i = right_start; i < right_end - right_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ right_bounds.grow(prim_boundbox);
+ }
+ }
left = BVHRange(left_bounds, left_start, left_end - left_start);
right = BVHRange(right_bounds, right_start, right_end - right_start);
}
@@ -295,11 +359,13 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
Mesh::Triangle t = mesh->get_triangle(prim_index);
const float3 *verts = &mesh->verts[0];
float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
+ v1 = get_unaligned_point(v1);
for(int i = 0; i < 3; i++) {
float3 v0 = v1;
int vindex = t.v[i];
v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
+ v1 = get_unaligned_point(v1);
float v0p = v0[dim];
float v1p = v1[dim];
@@ -339,6 +405,8 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh,
v0 = transform_point(tfm, v0);
v1 = transform_point(tfm, v1);
}
+ v0 = get_unaligned_point(v0);
+ v1 = get_unaligned_point(v1);
float v0p = v0[dim];
float v1p = v1[dim];
@@ -473,6 +541,7 @@ void BVHSpatialSplit::split_reference(const BVHBuild& builder,
/* intersect with original bounds. */
left_bounds.max[dim] = pos;
right_bounds.min[dim] = pos;
+
left_bounds.intersect(ref.bounds());
right_bounds.intersect(ref.bounds());
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
index aea8b2565e0..dbdb51f1a5b 100644
--- a/intern/cycles/bvh/bvh_split.h
+++ b/intern/cycles/bvh/bvh_split.h
@@ -24,6 +24,7 @@
CCL_NAMESPACE_BEGIN
class BVHBuild;
+struct Transform;
/* Object Split */
@@ -41,7 +42,9 @@ public:
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH);
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
void split(BVHRange& left,
BVHRange& right,
@@ -50,6 +53,19 @@ public:
protected:
BVHSpatialStorage *storage_;
vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
};
/* Spatial Split */
@@ -70,7 +86,9 @@ public:
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH);
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
void split(BVHBuild *builder,
BVHRange& left,
@@ -87,6 +105,8 @@ public:
protected:
BVHSpatialStorage *storage_;
vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
/* Lower-level functions which calculates boundaries of left and right nodes
* needed for spatial split.
@@ -132,6 +152,27 @@ protected:
float pos,
BoundBox& left_bounds,
BoundBox& right_bounds);
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
+
+ __forceinline float3 get_unaligned_point(const float3& point) const
+ {
+ if(aligned_space_ == NULL) {
+ return point;
+ }
+ else {
+ return transform_point(aligned_space_, point);
+ }
+ }
};
/* Mixed Object-Spatial Split */
@@ -148,19 +189,40 @@ public:
bool no_split;
+ BoundBox bounds;
+
+ BVHMixedSplit() {}
+
__forceinline BVHMixedSplit(BVHBuild *builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- int level)
+ int level,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL)
{
+ if(aligned_space == NULL) {
+ bounds = range.bounds();
+ }
+ else {
+ bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range,
+ &references->at(0),
+ *aligned_space);
+ }
/* find split candidates. */
- float area = range.bounds().safe_area();
+ float area = bounds.safe_area();
leafSAH = area * builder->params.primitive_cost(range.size());
nodeSAH = area * builder->params.node_cost(2);
- object = BVHObjectSplit(builder, storage, range, references, nodeSAH);
+ object = BVHObjectSplit(builder,
+ storage,
+ range,
+ references,
+ nodeSAH,
+ unaligned_heuristic,
+ aligned_space);
if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
BoundBox overlap = object.left_bounds;
@@ -171,7 +233,9 @@ public:
storage,
range,
references,
- nodeSAH);
+ nodeSAH,
+ unaligned_heuristic,
+ aligned_space);
}
}
@@ -181,7 +245,10 @@ public:
builder->range_within_max_leaf_size(range, *references));
}
- __forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
+ __forceinline void split(BVHBuild *builder,
+ BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range)
{
if(builder->params.use_spatial_split && minSAH == spatial.sah)
spatial.split(builder, left, right, range);
@@ -193,4 +260,3 @@ public:
CCL_NAMESPACE_END
#endif /* __BVH_SPLIT_H__ */
-
diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp
new file mode 100644
index 00000000000..a876c670914
--- /dev/null
+++ b/intern/cycles/bvh/bvh_unaligned.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "bvh_unaligned.h"
+
+#include "mesh.h"
+#include "object.h"
+
+#include "bvh_binning.h"
+#include "bvh_params.h"
+
+#include "util_boundbox.h"
+#include "util_debug.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+
+BVHUnaligned::BVHUnaligned(const vector<Object*>& objects)
+ : objects_(objects)
+{
+}
+
+Transform BVHUnaligned::compute_aligned_space(
+ const BVHObjectBinning& range,
+ const BVHReference *references) const
+{
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if(compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+Transform BVHUnaligned::compute_aligned_space(
+ const BVHRange& range,
+ const BVHReference *references) const
+{
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if(compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+bool BVHUnaligned::compute_aligned_space(const BVHReference& ref,
+ Transform *aligned_space) const
+{
+ const Object *object = objects_[ref.prim_object()];
+ const int packed_type = ref.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if(type & PRIMITIVE_CURVE) {
+ const int curve_index = ref.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve& curve = mesh->get_curve(curve_index);
+ const int key = curve.first_key + segment;
+ const float3 v1 = mesh->curve_keys[key],
+ v2 = mesh->curve_keys[key + 1];
+ float length;
+ const float3 axis = normalize_len(v2 - v1, &length);
+ if(length > 1e-6f) {
+ *aligned_space = make_transform_frame(axis);
+ return true;
+ }
+ }
+ *aligned_space = transform_identity();
+ return false;
+}
+
+BoundBox BVHUnaligned::compute_aligned_prim_boundbox(
+ const BVHReference& prim,
+ const Transform& aligned_space) const
+{
+ BoundBox bounds = BoundBox::empty;
+ const Object *object = objects_[prim.prim_object()];
+ const int packed_type = prim.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if(type & PRIMITIVE_CURVE) {
+ const int curve_index = prim.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve& curve = mesh->get_curve(curve_index);
+ curve.bounds_grow(segment,
+ &mesh->curve_keys[0],
+ &mesh->curve_radius[0],
+ aligned_space,
+ bounds);
+ }
+ else {
+ bounds = prim.bounds().transformed(&aligned_space);
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(
+ const BVHObjectBinning& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if(cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if(cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(
+ const BVHRange& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if(cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if(cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+Transform BVHUnaligned::compute_node_transform(
+ const BoundBox& bounds,
+ const Transform& aligned_space)
+{
+ Transform space = aligned_space;
+ space.x.w -= bounds.min.x;
+ space.y.w -= bounds.min.y;
+ space.z.w -= bounds.min.z;
+ float3 dim = bounds.max - bounds.min;
+ return transform_scale(1.0f / max(1e-18f, dim.x),
+ 1.0f / max(1e-18f, dim.y),
+ 1.0f / max(1e-18f, dim.z)) * space;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h
new file mode 100644
index 00000000000..4d0872f4a39
--- /dev/null
+++ b/intern/cycles/bvh/bvh_unaligned.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_UNALIGNED_H__
+#define __BVH_UNALIGNED_H__
+
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BoundBox;
+class BVHObjectBinning;
+class BVHRange;
+class BVHReference;
+struct Transform;
+class Object;
+
+/* Helper class to perform calculations needed for unaligned nodes. */
+class BVHUnaligned {
+public:
+ BVHUnaligned(const vector<Object*>& objects);
+
+ /* Calculate alignment for the oriented node for a given range. */
+ Transform compute_aligned_space(
+ const BVHObjectBinning& range,
+ const BVHReference *references) const;
+ Transform compute_aligned_space(
+ const BVHRange& range,
+ const BVHReference *references) const;
+
+ /* Calculate alignment for the oriented node for a given reference.
+ *
+ * Return true when space was calculated successfully.
+ */
+ bool compute_aligned_space(const BVHReference& ref,
+ Transform *aligned_space) const;
+
+ /* Calculate primitive's bounding box in given space. */
+ BoundBox compute_aligned_prim_boundbox(
+ const BVHReference& prim,
+ const Transform& aligned_space) const;
+
+ /* Calculate bounding box in given space. */
+ BoundBox compute_aligned_boundbox(
+ const BVHObjectBinning& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+ BoundBox compute_aligned_boundbox(
+ const BVHRange& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+
+ /* Calculate affine transform for node packing.
+ * Bounds will be in the range of 0..1.
+ */
+ static Transform compute_node_transform(const BoundBox& bounds,
+ const Transform& aligned_space);
+protected:
+ /* List of objects BVH is being created for. */
+ const vector<Object*>& objects_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_UNALIGNED_H__ */
+
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index f0adbc03e22..bd3969b2889 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -28,6 +28,22 @@ set(SRC
kernels/cuda/kernel.cu
)
+set(SRC_BVH_HEADERS
+ bvh/bvh.h
+ bvh/bvh_nodes.h
+ bvh/bvh_shadow_all.h
+ bvh/bvh_subsurface.h
+ bvh/bvh_traversal.h
+ bvh/bvh_volume.h
+ bvh/bvh_volume_all.h
+ bvh/qbvh_nodes.h
+ bvh/qbvh_shadow_all.h
+ bvh/qbvh_subsurface.h
+ bvh/qbvh_traversal.h
+ bvh/qbvh_volume.h
+ bvh/qbvh_volume_all.h
+)
+
set(SRC_HEADERS
kernel_accumulate.h
kernel_bake.h
@@ -140,23 +156,11 @@ set(SRC_SVM_HEADERS
set(SRC_GEOM_HEADERS
geom/geom.h
geom/geom_attribute.h
- geom/geom_bvh.h
- geom/geom_bvh_shadow.h
- geom/geom_bvh_subsurface.h
- geom/geom_bvh_traversal.h
- geom/geom_bvh_volume.h
- geom/geom_bvh_volume_all.h
geom/geom_curve.h
geom/geom_motion_curve.h
geom/geom_motion_triangle.h
geom/geom_object.h
geom/geom_primitive.h
- geom/geom_qbvh.h
- geom/geom_qbvh_shadow.h
- geom/geom_qbvh_subsurface.h
- geom/geom_qbvh_traversal.h
- geom/geom_qbvh_volume.h
- geom/geom_qbvh_volume_all.h
geom/geom_triangle.h
geom/geom_triangle_intersect.h
geom/geom_volume.h
@@ -212,7 +216,14 @@ if(WITH_CYCLES_CUDA_BINARIES)
endif()
# build for each arch
- set(cuda_sources kernels/cuda/kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS})
+ set(cuda_sources kernels/cuda/kernel.cu
+ ${SRC_HEADERS}
+ ${SRC_BVH_HEADERS}
+ ${SRC_SVM_HEADERS}
+ ${SRC_GEOM_HEADERS}
+ ${SRC_CLOSURE_HEADERS}
+ ${SRC_UTIL_HEADERS}
+ )
set(cuda_cubins)
macro(CYCLES_CUDA_KERNEL_ADD arch experimental)
@@ -312,6 +323,7 @@ add_library(cycles_kernel
${SRC}
${SRC_HEADERS}
${SRC_KERNELS_CPU_HEADERS}
+ ${SRC_BVH_HEADERS}
${SRC_CLOSURE_HEADERS}
${SRC_SVM_HEADERS}
${SRC_GEOM_HEADERS}
@@ -346,6 +358,7 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteratio
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_sum_all_radiance.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/bvh)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom)
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/bvh/bvh.h
index d0eedd3396a..59881738195 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -35,6 +35,13 @@ CCL_NAMESPACE_BEGIN
# define ccl_device_intersect ccl_device_inline
#endif
+/* bottom-most stack entry, indicating the end of traversal */
+#define ENTRYPOINT_SENTINEL 0x76543210
+
+/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
+#define BVH_STACK_SIZE 192
+#define BVH_QSTACK_SIZE 384
+
/* BVH intersection function variations */
#define BVH_INSTANCING 1
@@ -72,71 +79,73 @@ CCL_NAMESPACE_BEGIN
/* Common QBVH functions. */
#ifdef __QBVH__
-# include "geom_qbvh.h"
+# include "qbvh_nodes.h"
#endif
/* Regular BVH traversal */
+#include "bvh_nodes.h"
+
#define BVH_FUNCTION_NAME bvh_intersect
#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_traversal.h"
+#include "bvh_traversal.h"
#if defined(__INSTANCING__)
# define BVH_FUNCTION_NAME bvh_intersect_instancing
# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_hair
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
/* Subsurface scattering BVH traversal */
#if defined(__SUBSURFACE__)
# define BVH_FUNCTION_NAME bvh_intersect_subsurface
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_subsurface.h"
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_subsurface.h"
#endif
#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
-# define BVH_FUNCTION_FEATURES BVH_MOTION
-# include "geom_bvh_subsurface.h"
+# define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR
+# include "bvh_subsurface.h"
#endif
/* Volume BVH traversal */
#if defined(__VOLUME__)
# define BVH_FUNCTION_NAME bvh_intersect_volume
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_volume.h"
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_volume.h"
#endif
#if defined(__VOLUME__) && defined(__INSTANCING__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_volume.h"
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "bvh_volume.h"
#endif
#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_volume.h"
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR
+# include "bvh_volume.h"
#endif
/* Record all intersections - Shadow BVH traversal */
@@ -144,51 +153,51 @@ CCL_NAMESPACE_BEGIN
#if defined(__SHADOW_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_shadow.h"
+# include "bvh_shadow_all.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_shadow.h"
+# include "bvh_shadow_all.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
-# include "geom_bvh_shadow.h"
+# include "bvh_shadow_all.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_shadow.h"
+# include "bvh_shadow_all.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
-# include "geom_bvh_shadow.h"
+# include "bvh_shadow_all.h"
#endif
/* Record all intersections - Volume BVH traversal */
#if defined(__VOLUME_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_volume_all.h"
#endif
#if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "bvh_volume_all.h"
#endif
#if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR
+# include "bvh_volume_all.h"
#endif
#undef BVH_FEATURE
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h
new file mode 100644
index 00000000000..db2275b0ff8
--- /dev/null
+++ b/intern/cycles/kernel/bvh/bvh_nodes.h
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2011-2016, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and
+// 3-vector which might be faster.
+ccl_device_inline Transform bvh_unaligned_node_fetch_space(KernelGlobals *kg,
+ int node_addr,
+ int child)
+{
+ Transform space;
+ const int child_addr = node_addr + child * 3;
+ space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
+ space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
+ space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
+ space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+ return space;
+}
+
+#if !defined(__KERNEL_SSE2__)
+ccl_device_inline int bvh_aligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+
+ /* fetch node data */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3);
+
+ /* intersect ray against child nodes */
+ float c0lox = (node0.x - P.x) * idir.x;
+ float c0hix = (node0.z - P.x) * idir.x;
+ float c0loy = (node1.x - P.y) * idir.y;
+ float c0hiy = (node1.z - P.y) * idir.y;
+ float c0loz = (node2.x - P.z) * idir.z;
+ float c0hiz = (node2.z - P.z) * idir.z;
+ float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ float c1lox = (node0.y - P.x) * idir.x;
+ float c1hix = (node0.w - P.x) * idir.x;
+ float c1loy = (node1.y - P.y) * idir.y;
+ float c1hiy = (node1.w - P.y) * idir.y;
+ float c1loz = (node2.y - P.z) * idir.z;
+ float c1hiz = (node2.w - P.z) * idir.z;
+ float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ dist[0] = c0min;
+ dist[1] = c1min;
+
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+#else
+ return ((c0max >= c0min)? 1: 0) |
+ ((c1max >= c1min)? 2: 0);
+#endif
+}
+
+ccl_device_inline int bvh_aligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+
+ /* fetch node data */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3);
+
+ /* intersect ray against child nodes */
+ float c0lox = (node0.x - P.x) * idir.x;
+ float c0hix = (node0.z - P.x) * idir.x;
+ float c0loy = (node1.x - P.y) * idir.y;
+ float c0hiy = (node1.z - P.y) * idir.y;
+ float c0loz = (node2.x - P.z) * idir.z;
+ float c0hiz = (node2.z - P.z) * idir.z;
+ float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ float c1lox = (node0.y - P.x) * idir.x;
+ float c1hix = (node0.w - P.x) * idir.x;
+ float c1loy = (node1.y - P.y) * idir.y;
+ float c1hiy = (node1.w - P.y) * idir.y;
+ float c1loz = (node2.y - P.z) * idir.z;
+ float c1hiz = (node2.w - P.z) * idir.z;
+ float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ if(difl != 0.0f) {
+ float hdiff = 1.0f + difl;
+ float ldiff = 1.0f - difl;
+ if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
+ c0min = max(ldiff * c0min, c0min - extmax);
+ c0max = min(hdiff * c0max, c0max + extmax);
+ }
+ if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
+ c1min = max(ldiff * c1min, c1min - extmax);
+ c1max = min(hdiff * c1max, c1max + extmax);
+ }
+ }
+
+ dist[0] = c0min;
+ dist[1] = c1min;
+
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+#else
+ return ((c0max >= c0min)? 1: 0) |
+ ((c1max >= c1min)? 2: 0);
+#endif
+}
+
+ccl_device_inline bool bvh_unaligned_node_intersect_child(
+ KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float t,
+ int node_addr,
+ int child,
+ float dist[2])
+{
+ Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
+ float3 aligned_dir = transform_direction(&space, dir);
+ float3 aligned_P = transform_point(&space, P);
+ float3 nrdir = -bvh_inverse_direction(aligned_dir);
+ float3 lower_xyz = aligned_P * nrdir;
+ float3 upper_xyz = lower_xyz - nrdir;
+ const float near_x = min(lower_xyz.x, upper_xyz.x);
+ const float near_y = min(lower_xyz.y, upper_xyz.y);
+ const float near_z = min(lower_xyz.z, upper_xyz.z);
+ const float far_x = max(lower_xyz.x, upper_xyz.x);
+ const float far_y = max(lower_xyz.y, upper_xyz.y);
+ const float far_z = max(lower_xyz.z, upper_xyz.z);
+ const float tnear = max4(0.0f, near_x, near_y, near_z);
+ const float tfar = min4(t, far_x, far_y, far_z);
+ *dist = tnear;
+ return tnear <= tfar;
+}
+
+ccl_device_inline bool bvh_unaligned_node_intersect_child_robust(
+ KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float t,
+ const float difl,
+ int node_addr,
+ int child,
+ float dist[2])
+{
+ Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
+ float3 aligned_dir = transform_direction(&space, dir);
+ float3 aligned_P = transform_point(&space, P);
+ float3 nrdir = -bvh_inverse_direction(aligned_dir);
+ float3 tLowerXYZ = aligned_P * nrdir;
+ float3 tUpperXYZ = tLowerXYZ - nrdir;
+ const float near_x = min(tLowerXYZ.x, tUpperXYZ.x);
+ const float near_y = min(tLowerXYZ.y, tUpperXYZ.y);
+ const float near_z = min(tLowerXYZ.z, tUpperXYZ.z);
+ const float far_x = max(tLowerXYZ.x, tUpperXYZ.x);
+ const float far_y = max(tLowerXYZ.y, tUpperXYZ.y);
+ const float far_z = max(tLowerXYZ.z, tUpperXYZ.z);
+ const float tnear = max4(0.0f, near_x, near_y, near_z);
+ const float tfar = min4(t, far_x, far_y, far_z);
+ *dist = tnear;
+ if(difl != 0.0f) {
+ /* TODO(sergey): Same as for QBVH, needs a proper use. */
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ return round_down*tnear <= round_up*tfar;
+ }
+ else {
+ return tnear <= tfar;
+ }
+}
+
+ccl_device_inline int bvh_unaligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ int mask = 0;
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.x) & visibility))
+#endif
+ {
+ mask |= 1;
+ }
+ }
+ if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.y) & visibility))
+#endif
+ {
+ mask |= 2;
+ }
+ }
+ return mask;
+}
+
+ccl_device_inline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ int mask = 0;
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 0, &dist[0])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.x) & visibility))
+#endif
+ {
+ mask |= 1;
+ }
+ }
+ if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 1, &dist[1])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.y) & visibility))
+#endif
+ {
+ mask |= 2;
+ }
+ }
+ return mask;
+}
+
+ccl_device_inline int bvh_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect(kg,
+ P,
+ dir,
+ idir,
+ t,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect(kg,
+ P,
+ idir,
+ t,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+
+ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect_robust(kg,
+ P,
+ dir,
+ idir,
+ t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect_robust(kg,
+ P,
+ idir,
+ t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+#else /* !defined(__KERNEL_SSE2__) */
+
+int ccl_device_inline bvh_aligned_node_intersect(
+ KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + node_addr;
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ dist[0] = tminmax[0];
+ dist[1] = tminmax[1];
+
+ int mask = movemask(lrhit);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+int ccl_device_inline bvh_aligned_node_intersect_robust(
+ KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const float difl,
+ const float extmax,
+ const int nodeAddr,
+ const uint visibility,
+ float dist[2])
+{
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr;
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+
+ if(difl != 0.0f) {
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0);
+ float4 *tminmaxview = (float4*)&tminmax;
+ float& c0min = tminmaxview->x, &c1min = tminmaxview->y;
+ float& c0max = tminmaxview->z, &c1max = tminmaxview->w;
+ float hdiff = 1.0f + difl;
+ float ldiff = 1.0f - difl;
+ if(__float_as_int(cnodes.x) & PATH_RAY_CURVE) {
+ c0min = max(ldiff * c0min, c0min - extmax);
+ c0max = min(hdiff * c0max, c0max + extmax);
+ }
+ if(__float_as_int(cnodes.y) & PATH_RAY_CURVE) {
+ c1min = max(ldiff * c1min, c1min - extmax);
+ c1max = min(hdiff * c1max, c1max + extmax);
+ }
+ }
+
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ dist[0] = tminmax[0];
+ dist[1] = tminmax[1];
+
+ int mask = movemask(lrhit);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+int ccl_device_inline bvh_unaligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0);
+ Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1);
+
+ float3 aligned_dir0 = transform_direction(&space0, dir),
+ aligned_dir1 = transform_direction(&space1, dir);;
+ float3 aligned_P0 = transform_point(&space0, P),
+ aligned_P1 = transform_point(&space1, P);
+ float3 nrdir0 = -bvh_inverse_direction(aligned_dir0),
+ nrdir1 = -bvh_inverse_direction(aligned_dir1);
+
+ ssef lower_x = ssef(aligned_P0.x * nrdir0.x,
+ aligned_P1.x * nrdir1.x,
+ 0.0f, 0.0f),
+ lower_y = ssef(aligned_P0.y * nrdir0.y,
+ aligned_P1.y * nrdir1.y,
+ 0.0f,
+ 0.0f),
+ lower_z = ssef(aligned_P0.z * nrdir0.z,
+ aligned_P1.z * nrdir1.z,
+ 0.0f,
+ 0.0f);
+
+ ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f),
+ upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f),
+ upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f);
+
+ ssef tnear_x = min(lower_x, upper_x);
+ ssef tnear_y = min(lower_y, upper_y);
+ ssef tnear_z = min(lower_z, upper_z);
+ ssef tfar_x = max(lower_x, upper_x);
+ ssef tfar_y = max(lower_y, upper_y);
+ ssef tfar_z = max(lower_z, upper_z);
+
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ sseb vmask = tnear <= tfar;
+ dist[0] = tnear.f[0];
+ dist[1] = tnear.f[1];
+
+ int mask = (int)movemask(vmask);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+int ccl_device_inline bvh_unaligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const float difl,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0);
+ Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1);
+
+ float3 aligned_dir0 = transform_direction(&space0, dir),
+ aligned_dir1 = transform_direction(&space1, dir);;
+ float3 aligned_P0 = transform_point(&space0, P),
+ aligned_P1 = transform_point(&space1, P);
+ float3 nrdir0 = -bvh_inverse_direction(aligned_dir0),
+ nrdir1 = -bvh_inverse_direction(aligned_dir1);
+
+ ssef lower_x = ssef(aligned_P0.x * nrdir0.x,
+ aligned_P1.x * nrdir1.x,
+ 0.0f, 0.0f),
+ lower_y = ssef(aligned_P0.y * nrdir0.y,
+ aligned_P1.y * nrdir1.y,
+ 0.0f,
+ 0.0f),
+ lower_z = ssef(aligned_P0.z * nrdir0.z,
+ aligned_P1.z * nrdir1.z,
+ 0.0f,
+ 0.0f);
+
+ ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f),
+ upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f),
+ upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f);
+
+ ssef tnear_x = min(lower_x, upper_x);
+ ssef tnear_y = min(lower_y, upper_y);
+ ssef tnear_z = min(lower_z, upper_z);
+ ssef tfar_x = max(lower_x, upper_x);
+ ssef tfar_y = max(lower_y, upper_y);
+ ssef tfar_z = max(lower_z, upper_z);
+
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ sseb vmask;
+ if(difl != 0.0f) {
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ vmask = round_down*tnear <= round_up*tfar;
+ }
+ else {
+ vmask = tnear <= tfar;
+ }
+
+ dist[0] = tnear.f[0];
+ dist[1] = tnear.f[1];
+
+ int mask = (int)movemask(vmask);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+ccl_device_inline int bvh_node_intersect(KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect(kg,
+ P,
+ dir,
+ isect_near,
+ isect_far,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect(kg,
+ P,
+ dir,
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+
+ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect_robust(kg,
+ P,
+ dir,
+ isect_near,
+ isect_far,
+ difl,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect_robust(kg,
+ P,
+ dir,
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+#endif /* !defined(__KERNEL_SSE2__) */
diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index 4005489f77d..1869457f0c3 100644
--- a/intern/cycles/kernel/geom/geom_bvh_shadow.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-# include "geom_qbvh_shadow.h"
+# include "qbvh_shadow_all.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function, where various features can be
@@ -41,14 +47,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
* - likely and unlikely for if() statements
* - test restrict attribute for pointers
*/
-
+
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
@@ -72,9 +78,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -93,130 +102,87 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_ahild1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
- traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-# else
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
# endif
-
+ idir,
+ isect_t,
+ node_addr,
+ PATH_RAY_SHADOW,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
- traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-# else
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ PATH_RAY_SHADOW,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_ahild1 = __float_as_int(cnodes.w);
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
-
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_ahild1;
+ node_addr_ahild1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_ahild1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_ahild1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
- while(primAddr < primAddr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ while(prim_addr < prim_addr2) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
bool hit;
@@ -226,22 +192,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr);
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#endif
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
break;
}
#endif
@@ -253,6 +254,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* shadow ray early termination */
if(hit) {
+ /* Update number of hits now, so we do proper check on max bounces. */
+ (*num_hits)++;
+
/* detect if this surface has a shader with transparent shadows */
/* todo: optimize so primitive visibility flag indicates if
@@ -283,23 +287,20 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
return true;
}
- /* move on to next entry in intersections array */
- isect_array++;
- (*num_hits)++;
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
-
- isect_array->t = isect_t;
+ /* Move on to next entry in intersections array */
+ isect_array++;
}
- primAddr++;
+ prim_addr++;
}
}
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
@@ -317,21 +318,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
if(num_hits_in_instance) {
@@ -369,15 +373,18 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return false;
}
@@ -410,3 +417,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h
index 915e9415c93..18978efcfa3 100644
--- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/bvh_subsurface.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-# include "geom_qbvh_subsurface.h"
+# include "qbvh_subsurface.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for subsurface scattering, where
@@ -44,12 +50,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
+ int stack_ptr = 0;
+ int node_addr = kernel_tex_fetch(__object_node, subsurface_object);
/* ray parameters in registers */
float3 P = ray->P;
@@ -84,6 +90,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -100,127 +109,94 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* traversal loop */
do {
- do
- {
+ do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
- {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect_t,
+ node_addr,
+ PATH_RAY_ALL_VISIBILITY,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ PATH_RAY_ALL_VISIBILITY,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
triangle_intersect_subsurface(kg,
&isect_precalc,
ss_isect,
P,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -230,15 +206,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
motion_triangle_intersect_subsurface(kg,
ss_isect,
P,
dir,
ray->time,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -251,8 +227,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
}
}
}
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
}
ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
@@ -286,3 +262,4 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h
index ae919ef3f86..68a11b65ad7 100644
--- a/intern/cycles/kernel/geom/geom_bvh_traversal.h
+++ b/intern/cycles/kernel/bvh/bvh_traversal.h
@@ -18,7 +18,15 @@
*/
#ifdef __QBVH__
-# include "geom_qbvh_traversal.h"
+# include "qbvh_traversal.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+# define NODE_INTERSECT_ROBUST bvh_node_intersect_robust
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+# define NODE_INTERSECT_ROBUST bvh_aligned_node_intersect_robust
#endif
/* This is a template BVH traversal function, where various features can be
@@ -49,14 +57,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
* - likely and unlikely for if() statements
* - test restrict attribute for pointers
*/
-
+
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
float3 P = ray->P;
@@ -79,9 +87,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect->t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -100,174 +111,148 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
- float hdiff = 1.0f + difl;
- float ldiff = 1.0f - difl;
- if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
- c0min = max(ldiff * c0min, c0min - extmax);
- c0max = min(hdiff * c0max, c0max + extmax);
- }
- if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
- c1min = max(ldiff * c1min, c1min - extmax);
- c1max = min(hdiff * c1max, c1max + extmax);
- }
+ traverse_mask = NODE_INTERSECT_ROBUST(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
}
+ else
# endif
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility);
- traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility);
-# else
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-# endif
-
+ {
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
+ }
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
- float4 *tminmaxview = (float4*)&tminmax;
- float &c0min = tminmaxview->x, &c1min = tminmaxview->y;
- float &c0max = tminmaxview->z, &c1max = tminmaxview->w;
-
- float hdiff = 1.0f + difl;
- float ldiff = 1.0f - difl;
- if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
- c0min = max(ldiff * c0min, c0min - extmax);
- c0max = min(hdiff * c0max, c0max + extmax);
- }
- if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
- c1min = max(ldiff * c1min, c1min - extmax);
- c1max = min(hdiff * c1max, c1max + extmax);
- }
+ traverse_mask = NODE_INTERSECT_ROBUST(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
}
+ else
# endif
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility);
- traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility);
-# else
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
-# endif
+ {
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
+ }
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
BVH_DEBUG_NEXT_STEP();
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
+ for(; prim_addr < prim_addr2; prim_addr++) {
BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr))
+ {
/* shadow ray early termination */
#if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
#else
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
@@ -278,15 +263,26 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
+ for(; prim_addr < prim_addr2; prim_addr++) {
BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr))
+ {
/* shadow ray early termination */
# if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
# else
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
@@ -299,20 +295,47 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
+ for(; prim_addr < prim_addr2; prim_addr++) {
BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
bool hit;
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- else
- hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
if(hit) {
/* shadow ray early termination */
# if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
# else
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
@@ -327,7 +350,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
@@ -342,24 +365,27 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
BVH_DEBUG_NEXT_INSTANCE();
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* instance pop */
@@ -376,16 +402,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return (isect->prim != PRIM_NONE);
}
@@ -433,3 +462,5 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
+#undef NODE_INTERSECT_ROBUST
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h
index f3edf85d723..03499e94347 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume.h
+++ b/intern/cycles/kernel/bvh/bvh_volume.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_volume.h"
+# include "qbvh_volume.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for volumes, where
@@ -43,12 +49,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
float3 P = ray->P;
@@ -69,9 +75,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect->t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -90,143 +99,124 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
+ triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr);
}
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr);
+ motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr);
}
break;
}
@@ -239,7 +229,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -258,29 +248,32 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* instance pop */
@@ -298,16 +291,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_MOTION) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return (isect->prim != PRIM_NONE);
}
@@ -337,3 +333,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
index ec837212471..b5405e8e57b 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/bvh_volume_all.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_volume_all.h"
+# include "qbvh_volume_all.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for volumes, where
@@ -44,12 +50,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
@@ -73,9 +79,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -94,137 +103,109 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_array->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect_t,
+ node_addr,
+ visibility,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
-
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
bool hit;
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ visibility,
+ object,
+ prim_addr);
if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
+ /* Update number of hits now, so we do proper check on max bounces. */
num_hits++;
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
- isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
@@ -239,6 +220,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
+ /* Move on to next entry in intersections array */
+ isect_array++;
+ isect_array->t = isect_t;
}
}
break;
@@ -246,23 +230,28 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr);
if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
+ /* Update number of hits now, so we do proper check on max bounces. */
num_hits++;
# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
# endif
- isect_array->t = isect_t;
if(num_hits == max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
@@ -277,6 +266,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
+ /* Move on to next entry in intersections array */
+ isect_array++;
+ isect_array->t = isect_t;
}
}
break;
@@ -290,7 +282,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -311,29 +303,32 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
if(num_hits_in_instance) {
@@ -368,16 +363,19 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_MOTION) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return num_hits;
}
@@ -410,3 +408,4 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h
new file mode 100644
index 00000000000..4d8695bedec
--- /dev/null
+++ b/intern/cycles/kernel/bvh/qbvh_nodes.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2011-2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+struct QBVHStackItem {
+ int addr;
+ float dist;
+};
+
+/* TOOD(sergey): Investigate if using intrinsics helps for both
+ * stack item swap and float comparison.
+ */
+ccl_device_inline void qbvh_item_swap(QBVHStackItem *ccl_restrict a,
+ QBVHStackItem *ccl_restrict b)
+{
+ QBVHStackItem tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1,
+ QBVHStackItem *ccl_restrict s2,
+ QBVHStackItem *ccl_restrict s3)
+{
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+ if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+}
+
+ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1,
+ QBVHStackItem *ccl_restrict s2,
+ QBVHStackItem *ccl_restrict s3,
+ QBVHStackItem *ccl_restrict s4)
+{
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+ if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); }
+ if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); }
+ if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); }
+ if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
+}
+
+/* Axis-aligned nodes intersection */
+
+ccl_device_inline int qbvh_aligned_node_intersect(KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#else
+ const sse3f& org,
+#endif
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr + 1;
+#ifdef __KERNEL_AVX2__
+ const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x);
+ const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y);
+ const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z);
+ const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x);
+ const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y);
+ const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z);
+#else
+ const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x;
+ const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y;
+ const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z;
+ const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x;
+ const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y;
+ const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z;
+#endif
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, isect_near));
+ const ssef tfar = mini(mini(tfar_x, tfar_y), mini(tfar_z, isect_far));
+ const sseb vmask = cast(tnear) > cast(tfar);
+ int mask = (int)movemask(vmask)^0xf;
+#else
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ const sseb vmask = tnear <= tfar;
+ int mask = (int)movemask(vmask);
+#endif
+ *dist = tnear;
+ return mask;
+}
+
+ccl_device_inline int qbvh_aligned_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#else
+ const sse3f& P,
+#endif
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr + 1;
+#ifdef __KERNEL_AVX2__
+ const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x);
+ const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y);
+ const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z);
+ const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x);
+ const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y);
+ const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z);
+#else
+ const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x;
+ const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y;
+ const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z;
+ const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x;
+ const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y;
+ const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z;
+#endif
+
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ const sseb vmask = round_down*tnear <= round_up*tfar;
+ *dist = tnear;
+ return (int)movemask(vmask);
+}
+
+/* Unaligned nodes intersection */
+
+ccl_device_inline int qbvh_unaligned_node_intersect(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#endif
+ const sse3f& org,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1);
+ const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2);
+ const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3);
+
+ const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4);
+ const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5);
+ const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6);
+
+ const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7);
+ const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8);
+ const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9);
+
+ const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10);
+ const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11);
+ const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12);
+
+ const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z,
+ aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z,
+ aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z;
+
+ const ssef aligned_P_x = org.x*tfm_x_x + org.y*tfm_x_y + org.z*tfm_x_z + tfm_t_x,
+ aligned_P_y = org.x*tfm_y_x + org.y*tfm_y_y + org.z*tfm_y_z + tfm_t_y,
+ aligned_P_z = org.x*tfm_z_x + org.y*tfm_z_y + org.z*tfm_z_z + tfm_t_z;
+
+ const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f);
+ const ssef nrdir_x = neg_one / aligned_dir_x,
+ nrdir_y = neg_one / aligned_dir_y,
+ nrdir_z = neg_one / aligned_dir_z;
+
+ const ssef tlower_x = aligned_P_x * nrdir_x,
+ tlower_y = aligned_P_y * nrdir_y,
+ tlower_z = aligned_P_z * nrdir_z;
+
+ const ssef tupper_x = tlower_x - nrdir_x,
+ tupper_y = tlower_y - nrdir_y,
+ tupper_z = tlower_z - nrdir_z;
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear_x = mini(tlower_x, tupper_x);
+ const ssef tnear_y = mini(tlower_y, tupper_y);
+ const ssef tnear_z = mini(tlower_z, tupper_z);
+ const ssef tfar_x = maxi(tlower_x, tupper_x);
+ const ssef tfar_y = maxi(tlower_y, tupper_y);
+ const ssef tfar_z = maxi(tlower_z, tupper_z);
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = tnear <= tfar;
+ *dist = tnear;
+ return movemask(vmask);
+#else
+ const ssef tnear_x = min(tlower_x, tupper_x);
+ const ssef tnear_y = min(tlower_y, tupper_y);
+ const ssef tnear_z = min(tlower_z, tupper_z);
+ const ssef tfar_x = max(tlower_x, tupper_x);
+ const ssef tfar_y = max(tlower_y, tupper_y);
+ const ssef tfar_z = max(tlower_z, tupper_z);
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = tnear <= tfar;
+ *dist = tnear;
+ return movemask(vmask);
+#endif
+}
+
+ccl_device_inline int qbvh_unaligned_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#endif
+ const sse3f& P,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1);
+ const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2);
+ const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3);
+
+ const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4);
+ const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5);
+ const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6);
+
+ const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7);
+ const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8);
+ const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9);
+
+ const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10);
+ const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11);
+ const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12);
+
+ const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z,
+ aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z,
+ aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z;
+
+ const ssef aligned_P_x = P.x*tfm_x_x + P.y*tfm_x_y + P.z*tfm_x_z + tfm_t_x,
+ aligned_P_y = P.x*tfm_y_x + P.y*tfm_y_y + P.z*tfm_y_z + tfm_t_y,
+ aligned_P_z = P.x*tfm_z_x + P.y*tfm_z_y + P.z*tfm_z_z + tfm_t_z;
+
+ const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f);
+ const ssef nrdir_x = neg_one / aligned_dir_x,
+ nrdir_y = neg_one / aligned_dir_y,
+ nrdir_z = neg_one / aligned_dir_z;
+
+ const ssef tlower_x = aligned_P_x * nrdir_x,
+ tlower_y = aligned_P_y * nrdir_y,
+ tlower_z = aligned_P_z * nrdir_z;
+
+ const ssef tupper_x = tlower_x - nrdir_x,
+ tupper_y = tlower_y - nrdir_y,
+ tupper_z = tlower_z - nrdir_z;
+
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear_x = mini(tlower_x, tupper_x);
+ const ssef tnear_y = mini(tlower_y, tupper_y);
+ const ssef tnear_z = mini(tlower_z, tupper_z);
+ const ssef tfar_x = maxi(tlower_x, tupper_x);
+ const ssef tfar_y = maxi(tlower_y, tupper_y);
+ const ssef tfar_z = maxi(tlower_z, tupper_z);
+#else
+ const ssef tnear_x = min(tlower_x, tupper_x);
+ const ssef tnear_y = min(tlower_y, tupper_y);
+ const ssef tnear_z = min(tlower_z, tupper_z);
+ const ssef tfar_x = max(tlower_x, tupper_x);
+ const ssef tfar_y = max(tlower_y, tupper_y);
+ const ssef tfar_z = max(tlower_z, tupper_z);
+#endif
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = round_down*tnear <= round_up*tfar;
+ *dist = tnear;
+ return movemask(vmask);
+}
+
+/* Intersectors wrappers.
+ *
+ * They'll check node type and call appropriate intersection code.
+ */
+
+ccl_device_inline int qbvh_node_intersect(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#endif
+ const sse3f& org,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const float4 node = kernel_tex_fetch(__bvh_nodes, offset);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return qbvh_unaligned_node_intersect(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ org_idir,
+#endif
+ org,
+ dir,
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ dist);
+ }
+ else {
+ return qbvh_aligned_node_intersect(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ org_idir,
+#else
+ org,
+#endif
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ dist);
+ }
+}
+
+ccl_device_inline int qbvh_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#endif
+ const sse3f& P,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const float4 node = kernel_tex_fetch(__bvh_nodes, offset);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return qbvh_unaligned_node_intersect_robust(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ P_idir,
+#endif
+ P,
+ dir,
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ dist);
+ }
+ else {
+ return qbvh_aligned_node_intersect_robust(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ P_idir,
+#else
+ P,
+#endif
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ dist);
+ }
+}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
index edb5b5c78c3..34753ff067d 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -27,6 +27,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
@@ -39,12 +45,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* Ray parameters in registers. */
const float tmax = ray->t;
@@ -72,13 +78,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif
ssef tnear(0.0f), tfar(tmax);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
@@ -96,29 +106,53 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+# endif
+# if BVH_FEATURE(BVH_HAIR)
+ dir4,
+# endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -127,24 +161,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -152,86 +186,86 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
#ifdef __VISIBILITY_FLAG__
if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) {
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
#endif
- int primAddr = __float_as_int(leaf.x);
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
- while(primAddr < primAddr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ while(prim_addr < prim_addr2) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
bool hit;
@@ -241,22 +275,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr);
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#endif
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
break;
}
#endif
@@ -268,6 +337,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Shadow ray early termination. */
if(hit) {
+ /* Update number of hits now, so we do proper check on max bounces. */
+ (*num_hits)++;
+
/* detect if this surface has a shader with transparent shadows */
/* todo: optimize so primitive visibility flag indicates if
@@ -298,23 +370,21 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
return true;
}
- /* move on to next entry in intersections array */
- isect_array++;
- (*num_hits)++;
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
-
+ /* Move on to next entry in intersections array */
+ isect_array++;
isect_array->t = isect_t;
}
- primAddr++;
+ prim_addr++;
}
}
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
@@ -329,28 +399,33 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
if(num_hits_in_instance) {
@@ -383,21 +458,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(tmax);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return false;
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h
index 84512a8783c..03794e3a882 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h
@@ -25,6 +25,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
SubsurfaceIntersection *ss_isect,
@@ -41,12 +47,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
+ int stack_ptr = 0;
+ int node_addr = kernel_tex_fetch(__object_node, subsurface_object);
/* Ray parameters in registers. */
float3 P = ray->P;
@@ -82,13 +88,17 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif
ssef tnear(0.0f), tfar(isect_t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
@@ -106,29 +116,43 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+ if(child_mask != 0) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -137,24 +161,24 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -162,82 +186,82 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* Intersect ray against primitive, */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
triangle_intersect_subsurface(kg,
&isect_precalc,
ss_isect,
P,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -247,15 +271,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* Intersect ray against primitive. */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
motion_triangle_intersect_subsurface(kg,
ss_isect,
P,
dir,
ray->time,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -267,6 +291,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
break;
}
}
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h
new file mode 100644
index 00000000000..f82ff661495
--- /dev/null
+++ b/intern/cycles/kernel/bvh/qbvh_traversal.h
@@ -0,0 +1,505 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+# define NODE_INTERSECT_ROBUST qbvh_node_intersect_robust
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+# define NODE_INTERSECT_ROBUST qbvh_aligned_node_intersect_robust
+#endif
+
+ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ ,uint *lcg_state,
+ float difl,
+ float extmax
+#endif
+ )
+{
+ /* TODO(sergey):
+ * - Test if pushing distance on the stack helps (for non shadow rays).
+ * - Separate version for shadow rays.
+ * - Likely and unlikely for if() statements.
+ * - Test restrict attribute for pointers.
+ */
+
+ /* Traversal stack in CUDA thread-local memory. */
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
+ traversal_stack[0].dist = -FLT_MAX;
+
+ /* Traversal variables in registers. */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+ float node_dist = -FLT_MAX;
+
+ /* Ray parameters in registers. */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+#ifndef __KERNEL_SSE41__
+ if(!isfinite(P.x)) {
+ return false;
+ }
+#endif
+
+ isect->t = ray->t;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ isect->prim = PRIM_NONE;
+ isect->object = OBJECT_NONE;
+
+ BVH_DEBUG_INIT();
+
+ ssef tnear(0.0f), tfar(ray->t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
+ sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+
+#ifdef __KERNEL_AVX2__
+ float3 P_idir = P*idir;
+ sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+
+ /* Offsets to select the side that becomes the lower or upper bound. */
+ int near_x, near_y, near_z;
+ int far_x, far_y, far_z;
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* Traversal loop. */
+ do {
+ do {
+ /* Traverse internal nodes. */
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+ if(UNLIKELY(node_dist > isect->t)
+#ifdef __VISIBILITY_FLAG__
+ || (__float_as_uint(inodes.x) & visibility) == 0)
+#endif
+ {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ int child_mask;
+ ssef dist;
+
+ BVH_DEBUG_NEXT_STEP();
+
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ if(difl != 0.0f) {
+ /* NOTE: We extend all the child BB instead of fetching
+ * and checking visibility flags for each of the,
+ *
+ * Need to test if doing opposite would be any faster.
+ */
+ child_mask = NODE_INTERSECT_ROBUST(kg,
+ tnear,
+ tfar,
+# ifdef __KERNEL_AVX2__
+ P_idir4,
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+# endif
+# if BVH_FEATURE(BVH_HAIR)
+ dir4,
+# endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ &dist);
+ }
+ else
+#endif /* BVH_HAIR_MINIMUM_WIDTH */
+ {
+ child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
+#ifdef __KERNEL_AVX2__
+ P_idir4,
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+ }
+
+ if(child_mask != 0) {
+ float4 cnodes;
+ /* TODO(sergey): Investigate whether moving cnodes upwards
+ * gives a speedup (will be different cache pattern but will
+ * avoid extra check here),
+ */
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
+
+ /* One child is hit, continue with that child. */
+ int r = __bscf(child_mask);
+ float d0 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
+ node_dist = d0;
+ continue;
+ }
+
+ /* Two children are hit, push far child, and continue with
+ * closer child.
+ */
+ int c0 = __float_as_int(cnodes[r]);
+ r = __bscf(child_mask);
+ int c1 = __float_as_int(cnodes[r]);
+ float d1 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ if(d1 < d0) {
+ node_addr = c1;
+ node_dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+ continue;
+ }
+ else {
+ node_addr = c0;
+ node_dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ continue;
+ }
+ }
+
+ /* Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there.
+ */
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+
+ /* Three children are hit, push all onto stack and sort 3
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c2 = __float_as_int(cnodes[r]);
+ float d2 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ /* Four children are hit, push all onto stack and sort 4
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c3 = __float_as_int(cnodes[r]);
+ float d3 = ((float*)&dist)[r];
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
+ }
+
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ }
+
+ /* If node is leaf, fetch triangle list. */
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+
+#ifdef __VISIBILITY_FLAG__
+ if(UNLIKELY((node_dist > isect->t) ||
+ ((__float_as_uint(leaf.z) & visibility) == 0)))
+#else
+ if(UNLIKELY((node_dist > isect->t)))
+#endif
+ {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ int prim_addr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(prim_addr >= 0) {
+#endif
+ int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+
+ /* Primitive intersection. */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr)) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr)) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_MOTION) */
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ bool hit;
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ if(hit) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_HAIR) */
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* Instance push. */
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
+
+# if BVH_FEATURE(BVH_MOTION)
+ qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist, &ob_itfm);
+# else
+ qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist);
+# endif
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
+ traversal_stack[stack_ptr].dist = -FLT_MAX;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+
+ BVH_DEBUG_NEXT_INSTANCE();
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
+# endif
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+#undef NODE_INTERSECT
+#undef NODE_INTERSECT_ROBUST
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h
index ab2e530dd20..b4f334eb842 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume.h
@@ -26,6 +26,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect,
@@ -38,12 +44,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* Ray parameters in registers. */
float3 P = ray->P;
@@ -68,13 +74,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect->object = OBJECT_NONE;
ssef tnear(0.0f), tfar(ray->t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
@@ -92,29 +102,52 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+#ifdef __VISIBILITY_FLAG__
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if((__float_as_uint(inodes.x) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -123,24 +156,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -148,102 +181,102 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
+ triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, prim_addr);
}
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr);
+ motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, prim_addr);
}
break;
}
@@ -253,7 +286,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -268,34 +301,39 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* Pop. */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
@@ -309,21 +347,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return (isect->prim != PRIM_NONE);
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h
index 5546471b0e3..a877e5bb341 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h
@@ -26,6 +26,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
@@ -39,12 +45,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* Ray parameters in registers. */
const float tmax = ray->t;
@@ -72,13 +78,17 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif
ssef tnear(0.0f), tfar(isect_t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
@@ -96,29 +106,52 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+#ifdef __VISIBILITY_FLAG__
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if((__float_as_uint(inodes.x) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -127,24 +160,24 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -152,96 +185,94 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
bool hit;
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr);
if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
+ /* Update number of hits now, so we do proper check on max bounces. */
num_hits++;
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
- isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
@@ -256,30 +287,31 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
+ /* Move on to next entry in intersections array */
+ isect_array++;
+ isect_array->t = isect_t;
}
}
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, prim_addr);
if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
+ /* Update number of hits now, so we do proper check on max bounces. */
num_hits++;
# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
# endif
- isect_array->t = isect_t;
if(num_hits == max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
@@ -294,6 +326,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
+ /* Move on to next entry in intersections array */
+ isect_array++;
+ isect_array->t = isect_t;
}
}
break;
@@ -304,7 +339,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -320,35 +355,40 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
num_hits_in_instance = 0;
isect_array->t = isect_t;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* Pop. */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
@@ -379,23 +419,30 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
isect_t = tmax;
isect_array->t = isect_t;
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return num_hits;
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index c94a5384d1f..d2c7edb11ea 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -15,27 +15,6 @@
* limitations under the License.
*/
-/* bottom-most stack entry, indicating the end of traversal */
-#define ENTRYPOINT_SENTINEL 0x76543210
-
-/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
-#define BVH_STACK_SIZE 192
-#define BVH_QSTACK_SIZE 384
-#define BVH_NODE_SIZE 4
-#define BVH_NODE_LEAF_SIZE 1
-#define BVH_QNODE_SIZE 7
-#define BVH_QNODE_LEAF_SIZE 1
-#define TRI_NODE_SIZE 3
-
-/* silly workaround for float extended precision that happens when compiling
- * without sse support on x86, it results in different results for float ops
- * that you would otherwise expect to compare correctly */
-#if !defined(__i386__) || defined(__SSE__)
-# define NO_EXTENDED_PRECISION
-#else
-# define NO_EXTENDED_PRECISION volatile
-#endif
-
#include "geom_attribute.h"
#include "geom_object.h"
#include "geom_triangle.h"
@@ -45,5 +24,4 @@
#include "geom_curve.h"
#include "geom_volume.h"
#include "geom_primitive.h"
-#include "geom_bvh.h"
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index 8894843997c..292e1bfca0e 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -450,8 +450,8 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
else if(level == 1) {
/* the maximum recursion depth is reached.
- * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
- * dP* is reversed if necessary.*/
+ * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
+ * dP* is reversed if necessary.*/
float t = isect->t;
float u = 0.0f;
float gd = 0.0f;
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index ffe55529110..2fb8e219884 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -47,13 +47,13 @@ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
}
-ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3])
+ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3])
{
if(step == numsteps) {
/* center step: regular vertex location */
- verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ verts[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
}
else {
/* center step not store in this array */
@@ -62,19 +62,19 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3
offset += step*numverts;
- verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
}
}
-ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3])
+ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3])
{
if(step == numsteps) {
/* center step: regular vertex location */
- normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
- normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
- normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
+ normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
}
else {
/* center step not stored in this array */
@@ -83,9 +83,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float
offset += step*numverts;
- normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
}
}
@@ -107,7 +107,7 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i
/* fetch vertex coordinates */
float3 next_verts[3];
- float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts);
@@ -259,7 +259,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD
/* fetch vertex coordinates */
float3 verts[3], next_verts[3];
- float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts);
diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h
deleted file mode 100644
index 2a2d7822eee..00000000000
--- a/intern/cycles/kernel/geom/geom_qbvh.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2011-2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-struct QBVHStackItem {
- int addr;
- float dist;
-};
-
-/* TOOD(sergey): Investigate if using intrinsics helps for both
- * stack item swap and float comparison.
- */
-ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a,
- QBVHStackItem *__restrict b)
-{
- QBVHStackItem tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
-ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1,
- QBVHStackItem *__restrict s2,
- QBVHStackItem *__restrict s3)
-{
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
- if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
-}
-
-ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1,
- QBVHStackItem *__restrict s2,
- QBVHStackItem *__restrict s3,
- QBVHStackItem *__restrict s4)
-{
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
- if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); }
- if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); }
- if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); }
- if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
-}
-
-ccl_device_inline int qbvh_node_intersect(KernelGlobals *__restrict kg,
- const ssef& tnear,
- const ssef& tfar,
-#ifdef __KERNEL_AVX2__
- const sse3f& org_idir,
-#else
- const sse3f& org,
-#endif
- const sse3f& idir,
- const int near_x,
- const int near_y,
- const int near_z,
- const int far_x,
- const int far_y,
- const int far_z,
- const int nodeAddr,
- ssef *__restrict dist)
-{
- const int offset = nodeAddr*BVH_QNODE_SIZE;
-#ifdef __KERNEL_AVX2__
- const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x);
- const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y);
- const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z);
- const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x);
- const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y);
- const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z);
-#else
- const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x;
- const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y;
- const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z;
- const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x;
- const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y;
- const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z;
-#endif
-
-#ifdef __KERNEL_SSE41__
- const ssef tNear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, tnear));
- const ssef tFar = mini(mini(tfar_x, tfar_y), mini(tfar_z, tfar));
- const sseb vmask = cast(tNear) > cast(tFar);
- int mask = (int)movemask(vmask)^0xf;
-#else
- const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear);
- const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar);
- const sseb vmask = tNear <= tFar;
- int mask = (int)movemask(vmask);
-#endif
- *dist = tNear;
- return mask;
-}
-
-ccl_device_inline int qbvh_node_intersect_robust(KernelGlobals *__restrict kg,
- const ssef& tnear,
- const ssef& tfar,
-#ifdef __KERNEL_AVX2__
- const sse3f& P_idir,
-#else
- const sse3f& P,
-#endif
- const sse3f& idir,
- const int near_x,
- const int near_y,
- const int near_z,
- const int far_x,
- const int far_y,
- const int far_z,
- const int nodeAddr,
- const float difl,
- ssef *__restrict dist)
-{
- const int offset = nodeAddr*BVH_QNODE_SIZE;
-#ifdef __KERNEL_AVX2__
- const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x);
- const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y);
- const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z);
- const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x);
- const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y);
- const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z);
-#else
- const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x;
- const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y;
- const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z;
- const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x;
- const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y;
- const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z;
-#endif
-
- const float round_down = 1.0f - difl;
- const float round_up = 1.0f + difl;
- const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear);
- const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar);
- const sseb vmask = round_down*tNear <= round_up*tFar;
- *dist = tNear;
- return (int)movemask(vmask);
-}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
deleted file mode 100644
index 738d08ac6fc..00000000000
--- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
- * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
- * BVH_MOTION: motion blur rendering
- *
- */
-
-ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- ,uint *lcg_state,
- float difl,
- float extmax
-#endif
- )
-{
- /* TODO(sergey):
- * - Test if pushing distance on the stack helps (for non shadow rays).
- * - Separate version for shadow rays.
- * - Likely and unlikely for if() statements.
- * - Test restrict attribute for pointers.
- */
-
- /* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
- traversalStack[0].dist = -FLT_MAX;
-
- /* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
- float nodeDist = -FLT_MAX;
-
- /* Ray parameters in registers. */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
-#ifndef __KERNEL_SSE41__
- if(!isfinite(P.x)) {
- return false;
- }
-#endif
-
- isect->t = ray->t;
- isect->u = 0.0f;
- isect->v = 0.0f;
- isect->prim = PRIM_NONE;
- isect->object = OBJECT_NONE;
-
- BVH_DEBUG_INIT();
-
- ssef tnear(0.0f), tfar(ray->t);
- sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-
-#ifdef __KERNEL_AVX2__
- float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
-
- /* Offsets to select the side that becomes the lower or upper bound. */
- int near_x, near_y, near_z;
- int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
-
- IsectPrecalc isect_precalc;
- triangle_intersect_precalc(dir, &isect_precalc);
-
- /* Traversal loop. */
- do {
- do {
- /* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- if(UNLIKELY(nodeDist > isect->t)) {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- int traverseChild;
- ssef dist;
-
- BVH_DEBUG_NEXT_STEP();
-
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- if(difl != 0.0f) {
- /* NOTE: We extend all the child BB instead of fetching
- * and checking visibility flags for each of the,
- *
- * Need to test if doing opposite would be any faster.
- */
- traverseChild = qbvh_node_intersect_robust(kg,
- tnear,
- tfar,
-# ifdef __KERNEL_AVX2__
- P_idir4,
-# else
- org,
-# endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- difl,
- &dist);
- }
- else
-#endif /* BVH_HAIR_MINIMUM_WIDTH */
- {
- traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
-#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
-#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
- }
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
-
- /* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- float d0 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
- nodeDist = d0;
- continue;
- }
-
- /* Two children are hit, push far child, and continue with
- * closer child.
- */
- int c0 = __float_as_int(cnodes[r]);
- r = __bscf(traverseChild);
- int c1 = __float_as_int(cnodes[r]);
- float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- if(d1 < d0) {
- nodeAddr = c1;
- nodeDist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
- continue;
- }
- else {
- nodeAddr = c0;
- nodeDist = d0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- continue;
- }
- }
-
- /* Here starts the slow path for 3 or 4 hit children. We push
- * all nodes onto the stack to sort them there.
- */
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
-
- /* Three children are hit, push all onto stack and sort 3
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c2 = __float_as_int(cnodes[r]);
- float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- /* Four children are hit, push all onto stack and sort 4
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c3 = __float_as_int(cnodes[r]);
- float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
- }
-
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- }
-
- /* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
-
-#ifdef __VISIBILITY_FLAG__
- if(UNLIKELY((nodeDist > isect->t) || ((__float_as_uint(leaf.z) & visibility) == 0)))
-#else
- if(UNLIKELY((nodeDist > isect->t)))
-#endif
- {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- int primAddr = __float_as_int(leaf.x);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
-
- /* Primitive intersection. */
- switch(type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_MOTION) */
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
- BVH_DEBUG_NEXT_STEP();
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- bool hit;
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- else
- hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- if(hit) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_HAIR) */
- }
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
-
-# if BVH_FEATURE(BVH_MOTION)
- qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_itfm);
-# else
- qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist);
-# endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect->t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
- traversalStack[stackPtr].dist = -FLT_MAX;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
-
- BVH_DEBUG_NEXT_INSTANCE();
- }
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* Instance pop. */
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
-# else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-# endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect->t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return (isect->prim != PRIM_NONE);
-}
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index 995dfac5b09..0c2351e1d1b 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -27,12 +27,11 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ const float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ const float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
- float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
-
/* return normal */
if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
return normalize(cross(v2 - v0, v1 - v0));
@@ -44,11 +43,10 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int prim, float u, float v, float3 *P, float3 *Ng, int *shader)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
/* compute point */
float t = 1.0f - u - v;
@@ -71,11 +69,10 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int
ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3])
{
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
}
/* Interpolate smooth vertex normal from vertices */
@@ -83,11 +80,10 @@ ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3
ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, float u, float v)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
- float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
- float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
+ float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
+ float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
return normalize((1.0f - u - v)*n2 + u*n0 + v*n1);
}
@@ -97,11 +93,10 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, flo
ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_space float3 *dPdu, ccl_addr_space float3 *dPdv)
{
/* fetch triangle vertex coordinates */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ const float3 p0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ const float3 p1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ const float3 p2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
/* compute derivatives of P w.r.t. uv */
*dPdu = (p0 - p2);
@@ -119,11 +114,11 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
- float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
- float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
- float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
+ float f0 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.x);
+ float f1 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.y);
+ float f2 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.z);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
@@ -162,11 +157,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
- float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index b6dfc769012..fc081bda525 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -106,9 +106,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -202,9 +203,10 @@ ccl_device_inline void triangle_intersect_subsurface(
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -324,9 +326,10 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
@@ -381,9 +384,10 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
P = P + D*t;
#ifdef __INTERSECTION_REFINE__
- const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 42314756f02..08f6f457805 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -42,6 +42,7 @@
#define ccl_constant
#define ccl_may_alias
#define ccl_addr_space
+#define ccl_restrict __restrict__
/* No assert supported for CUDA */
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index a5708448e23..8505cb85576 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -39,6 +39,7 @@
#define ccl_global __global
#define ccl_local __local
#define ccl_private __private
+#define ccl_restrict restrict
#ifdef __SPLIT_KERNEL__
# define ccl_addr_space __global
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 736a884f819..93c4bd3f7d5 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -51,8 +51,8 @@ ccl_device float area_light_sample(float3 P,
bool sample_coord)
{
/* In our name system we're using P for the center,
- * which is o in the paper.
- */
+ * which is o in the paper.
+ */
float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
float axisu_len, axisv_len;
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 3c3503eab8b..d5b31037723 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -25,6 +25,7 @@
#include "kernel_camera.h"
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 94598e2565e..731dc0407c5 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -309,7 +309,7 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b
state->num_samples = state->num_samples*num_branches;
}
-ccl_device_inline uint lcg_state_init(RNG *rng, const ccl_addr_space PathState *state, uint scramble)
+ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble)
{
return lcg_init(*rng + state->rng_offset + state->sample*scramble);
}
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 245d236ff97..5ba262c1044 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -25,7 +25,8 @@
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes)
-KERNEL_TEX(float4, texture_float4, __tri_storage)
+KERNEL_TEX(float4, texture_float4, __prim_tri_verts)
+KERNEL_TEX(uint, texture_uint, __prim_tri_index)
KERNEL_TEX(uint, texture_uint, __prim_type)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index)
@@ -39,8 +40,7 @@ KERNEL_TEX(float4, texture_float4, __objects_vector)
/* triangles */
KERNEL_TEX(uint, texture_uint, __tri_shader)
KERNEL_TEX(float4, texture_float4, __tri_vnormal)
-KERNEL_TEX(float4, texture_float4, __tri_vindex)
-KERNEL_TEX(float4, texture_float4, __tri_verts)
+KERNEL_TEX(uint4, texture_uint4, __tri_vindex)
/* curves */
KERNEL_TEX(float4, texture_float4, __curves)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 76d2a6b98e6..5de58ba28ed 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -292,11 +292,14 @@ enum PathRayFlag {
PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */
PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */
- PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024),
+ /* Special flag to tag unaligned BVH nodes. */
+ PATH_RAY_NODE_UNALIGNED = 2048,
- PATH_RAY_MIS_SKIP = 2048,
- PATH_RAY_DIFFUSE_ANCESTOR = 4096,
- PATH_RAY_SINGLE_PASS_DONE = 8192,
+ PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024|2048),
+
+ PATH_RAY_MIS_SKIP = 4096,
+ PATH_RAY_DIFFUSE_ANCESTOR = 8192,
+ PATH_RAY_SINGLE_PASS_DONE = 16384,
};
/* Closure Label */
@@ -769,7 +772,7 @@ typedef ccl_addr_space struct ShaderData {
int type;
/* parametric coordinates
- * - barycentric weights for triangles */
+ * - barycentric weights for triangles */
float u;
float v;
/* object id if there is one, ~0 otherwise */
@@ -792,14 +795,14 @@ typedef ccl_addr_space struct ShaderData {
#endif
#ifdef __DPDU__
/* differential of P w.r.t. parametric coordinates. note that dPdu is
- * not readily suitable as a tangent for shading on triangles. */
+ * not readily suitable as a tangent for shading on triangles. */
float3 dPdu;
float3 dPdv;
#endif
#ifdef __OBJECT_MOTION__
/* object <-> world space transformations, cached to avoid
- * re-interpolating them constantly for shading */
+ * re-interpolating them constantly for shading */
Transform ob_tfm;
Transform ob_itfm;
#endif
@@ -1171,11 +1174,11 @@ typedef ccl_addr_space struct DebugData {
#define QUEUE_EMPTY_SLOT -1
/*
-* Queue 1 - Active rays
-* Queue 2 - Background queue
-* Queue 3 - Shadow ray cast kernel - AO
-* Queeu 4 - Shadow ray cast kernel - direct lighting
-*/
+ * Queue 1 - Active rays
+ * Queue 2 - Background queue
+ * Queue 3 - Shadow ray cast kernel - AO
+ * Queeu 4 - Shadow ray cast kernel - direct lighting
+ */
#define NUM_QUEUES 4
/* Queue names */
diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl
index aad06ed5c76..37907cd8fdc 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel.cl
@@ -35,6 +35,7 @@
# include "../../kernel_montecarlo.h"
# include "../../kernel_projection.h"
# include "../../geom/geom.h"
+# include "../../bvh/bvh.h"
# include "../../kernel_accumulate.h"
# include "../../kernel_camera.h"
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index ebe739ebd0e..2bb2be5e6b3 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -47,6 +47,7 @@
#include "kernel_camera.h"
#include "kernels/cpu/kernel_cpu_image.h"
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_projection.h"
#include "kernel_accumulate.h"
@@ -912,7 +913,7 @@ bool OSLRenderServices::texture(ustring filename,
#endif
bool status;
- if(filename[0] == '@') {
+ if(filename.length() && filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t);
@@ -993,7 +994,7 @@ bool OSLRenderServices::texture3d(ustring filename,
}
bool status;
- if(filename[0] == '@') {
+ if(filename.length() && filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 49030f33c26..b43f8402d42 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -81,6 +81,7 @@ set(SRC_OSL
node_wireframe.osl
node_hair_bsdf.osl
node_uv_map.osl
+ node_rgb_to_bw.osl
)
set(SRC_OSL_HEADERS
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index a00401845c8..7cd2922dd4f 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -88,7 +88,7 @@ shader node_image_texture(
string color_space = "sRGB",
string projection = "flat",
string interpolation = "smartcubic",
- string wrap = "periodic",
+ string extension = "periodic",
float projection_blend = 0.0,
int is_float = 1,
int use_alpha = 1,
@@ -108,7 +108,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
else if (projection == "box") {
/* object space normal */
@@ -184,7 +184,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[0] * tmp_alpha;
}
if (weight[1] > 0.0) {
@@ -195,7 +195,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[1] * tmp_alpha;
}
if (weight[2] > 0.0) {
@@ -206,7 +206,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[2] * tmp_alpha;
}
}
@@ -219,7 +219,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
else if (projection == "tube") {
point projected = map_to_tube(texco_remap_square(p));
@@ -230,6 +230,6 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
}
diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl
new file mode 100644
index 00000000000..903dfcdc881
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_rgb_to_bw(
+ color Color = 0.0,
+ output float Val = 0.0)
+{
+ Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722;
+}
+
diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h
index e1c7e2cea99..88d6dab04d0 100644
--- a/intern/cycles/kernel/split/kernel_split_common.h
+++ b/intern/cycles/kernel/split/kernel_split_common.h
@@ -31,6 +31,7 @@
#include "kernel_camera.h"
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index aa9c07c867e..44732734c31 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -72,8 +72,16 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
uint width = info.x;
uint height = info.y;
uint offset = info.z;
- uint periodic = (info.w & 0x1);
- uint interpolation = info.w >> 1;
+
+ /* Image Options */
+ uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR;
+ uint extension;
+ if(info.w & (1 << 1))
+ extension = EXTENSION_REPEAT;
+ else if(info.w & (1 << 2))
+ extension = EXTENSION_EXTEND;
+ else
+ extension = EXTENSION_CLIP;
float4 r;
int ix, iy, nix, niy;
@@ -81,22 +89,26 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
svm_image_texture_frac(x*width, &ix);
svm_image_texture_frac(y*height, &iy);
- if(periodic) {
+ if(extension == EXTENSION_REPEAT) {
ix = svm_image_texture_wrap_periodic(ix, width);
iy = svm_image_texture_wrap_periodic(iy, height);
}
- else {
+ else if(extension == EXTENSION_CLIP) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f)
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else { /* EXTENSION_EXTEND */
ix = svm_image_texture_wrap_clamp(ix, width);
iy = svm_image_texture_wrap_clamp(iy, height);
-
}
+
r = svm_image_texture_read(kg, id, offset + ix + iy*width);
}
- else { /* We default to linear interpolation if it is not closest */
+ else { /* INTERPOLATION_LINEAR */
float tx = svm_image_texture_frac(x*width - 0.5f, &ix);
float ty = svm_image_texture_frac(y*height - 0.5f, &iy);
- if(periodic) {
+ if(extension == EXTENSION_REPEAT) {
ix = svm_image_texture_wrap_periodic(ix, width);
iy = svm_image_texture_wrap_periodic(iy, height);
@@ -104,14 +116,17 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
niy = svm_image_texture_wrap_periodic(iy+1, height);
}
else {
- ix = svm_image_texture_wrap_clamp(ix, width);
- iy = svm_image_texture_wrap_clamp(iy, height);
-
+ if(extension == EXTENSION_CLIP) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
nix = svm_image_texture_wrap_clamp(ix+1, width);
niy = svm_image_texture_wrap_clamp(iy+1, height);
+ ix = svm_image_texture_wrap_clamp(ix, width);
+ iy = svm_image_texture_wrap_clamp(iy, height);
}
-
r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width);
r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width);
r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width);
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index ecde2e99a7b..614620c14af 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -1076,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device,
}
}
+uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot)
+{
+ uint8_t options = 0;
+
+ /* Image Options are packed into one uint:
+ * bit 0 -> Interpolation
+ * bit 1 + 2 + 3-> Extension */
+ if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST)
+ options |= (1 << 0);
+
+ if(images[type][slot]->extension == EXTENSION_REPEAT)
+ options |= (1 << 1);
+ else if(images[type][slot]->extension == EXTENSION_EXTEND)
+ options |= (1 << 2);
+ else /* EXTENSION_CLIP */
+ options |= (1 << 3);
+
+ return options;
+}
+
void ImageManager::device_pack_images(Device *device,
DeviceScene *dscene,
Progress& /*progess*/)
@@ -1107,11 +1127,9 @@ void ImageManager::device_pack_images(Device *device,
device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot];
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
+
+ info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
@@ -1139,11 +1157,8 @@ void ImageManager::device_pack_images(Device *device,
/* todo: support 3D textures, only CPU for now */
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
+ info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 01d02f4dbec..07998684b23 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -122,6 +122,8 @@ private:
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
string name_from_type(int type);
+ uint8_t pack_image_options(ImageDataType type, size_t slot);
+
void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess);
void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot);
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 764a925983e..661719ed545 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -73,6 +73,37 @@ void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float
bounds.grow(upper, mr);
}
+void Mesh::Curve::bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform& aligned_space,
+ BoundBox& bounds) const
+{
+ float3 P[4];
+
+ P[0] = curve_keys[max(first_key + k - 1,first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
+
+ P[0] = transform_point(&aligned_space, P[0]);
+ P[1] = transform_point(&aligned_space, P[1]);
+ P[2] = transform_point(&aligned_space, P[2]);
+ P[3] = transform_point(&aligned_space, P[3]);
+
+ float3 lower;
+ float3 upper;
+
+ curvebounds(&lower.x, &upper.x, P, 0);
+ curvebounds(&lower.y, &upper.y, P, 1);
+ curvebounds(&lower.z, &upper.z, P, 2);
+
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
/* Mesh */
NODE_DEFINE(Mesh)
@@ -472,30 +503,19 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
}
}
-void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
+void Mesh::pack_verts(const vector<uint>& tri_prim_index,
+ uint4 *tri_vindex,
+ size_t vert_offset,
+ size_t tri_offset)
{
- size_t verts_size = verts.size();
-
- if(verts_size) {
- float3 *verts_ptr = &verts[0];
-
- for(size_t i = 0; i < verts_size; i++) {
- float3 p = verts_ptr[i];
- tri_verts[i] = make_float4(p.x, p.y, p.z, 0.0f);
- }
- }
-
- size_t triangles_size = num_triangles();
-
+ const size_t triangles_size = num_triangles();
if(triangles_size) {
for(size_t i = 0; i < triangles_size; i++) {
Triangle t = get_triangle(i);
-
- tri_vindex[i] = make_float4(
- __int_as_float(t.v[0] + vert_offset),
- __int_as_float(t.v[1] + vert_offset),
- __int_as_float(t.v[2] + vert_offset),
- 0);
+ tri_vindex[i] = make_uint4(t.v[0] + vert_offset,
+ t.v[1] + vert_offset,
+ t.v[2] + vert_offset,
+ tri_prim_index[i + tri_offset]);
}
}
}
@@ -533,7 +553,11 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s
}
}
-void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
+void Mesh::compute_bvh(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total)
{
if(progress->get_cancel())
return;
@@ -564,6 +588,7 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_qbvh = params->use_qbvh;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves;
delete bvh;
bvh = BVH::create(bparams, objects);
@@ -1070,42 +1095,82 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
}
}
-void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void MeshManager::mesh_calc_offset(Scene *scene)
{
- /* count and update offsets */
size_t vert_size = 0;
size_t tri_size = 0;
-
size_t curve_key_size = 0;
size_t curve_size = 0;
foreach(Mesh *mesh, scene->meshes) {
mesh->vert_offset = vert_size;
mesh->tri_offset = tri_size;
-
mesh->curvekey_offset = curve_key_size;
mesh->curve_offset = curve_size;
vert_size += mesh->verts.size();
tri_size += mesh->num_triangles();
-
curve_key_size += mesh->curve_keys.size();
curve_size += mesh->num_curves();
}
+}
+void MeshManager::device_update_mesh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ bool for_displacement,
+ Progress& progress)
+{
+ /* Count. */
+ size_t vert_size = 0;
+ size_t tri_size = 0;
+ size_t curve_key_size = 0;
+ size_t curve_size = 0;
+ foreach(Mesh *mesh, scene->meshes) {
+ vert_size += mesh->verts.size();
+ tri_size += mesh->num_triangles();
+ curve_key_size += mesh->curve_keys.size();
+ curve_size += mesh->num_curves();
+ }
+ /* Create mapping from triangle to primitive triangle array. */
+ vector<uint> tri_prim_index(tri_size);
+ if(for_displacement) {
+ /* For displacement kernels we do some trickery to make them believe
+ * we've got all required data ready. However, that data is different
+ * from final render kernels since we don't have BVH yet, so can't
+ * really use same semantic of arrays.
+ */
+ foreach(Mesh *mesh, scene->meshes) {
+ for(size_t i = 0; i < mesh->num_triangles(); ++i) {
+ tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset);
+ }
+ }
+ }
+ else {
+ PackedBVH& pack = bvh->pack;
+ for(size_t i = 0; i < pack.prim_index.size(); ++i) {
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i];
+ }
+ }
+ }
+ /* Fill in all the arrays. */
if(tri_size != 0) {
/* normals */
progress.set_status("Updating Mesh", "Computing normals");
uint *tri_shader = dscene->tri_shader.resize(tri_size);
float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
- float4 *tri_verts = dscene->tri_verts.resize(vert_size);
- float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
foreach(Mesh *mesh, scene->meshes) {
- mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]);
- mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
-
+ mesh->pack_normals(scene,
+ &tri_shader[mesh->tri_offset],
+ &vnormal[mesh->vert_offset]);
+ mesh->pack_verts(tri_prim_index,
+ &tri_vindex[mesh->tri_offset],
+ mesh->vert_offset,
+ mesh->tri_offset);
if(progress.get_cancel()) return;
}
@@ -1114,10 +1179,8 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__tri_shader", dscene->tri_shader);
device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
- device->tex_alloc("__tri_verts", dscene->tri_verts);
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
}
-
if(curve_size != 0) {
progress.set_status("Updating Mesh", "Copying Strands to device");
@@ -1132,6 +1195,19 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__curve_keys", dscene->curve_keys);
device->tex_alloc("__curves", dscene->curves);
}
+ if(for_displacement) {
+ float4 *prim_tri_verts = dscene->prim_tri_verts.resize(tri_size * 3);
+ foreach(Mesh *mesh, scene->meshes) {
+ for(size_t i = 0; i < mesh->num_triangles(); ++i) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ size_t offset = 3 * (i + mesh->tri_offset);
+ prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]);
+ prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]);
+ prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]);
+ }
+ }
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
+ }
}
void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -1146,6 +1222,7 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.top_level = true;
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1170,9 +1247,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size());
device->tex_alloc("__object_node", dscene->object_node);
}
- if(pack.tri_storage.size()) {
- dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size());
- device->tex_alloc("__tri_storage", dscene->tri_storage);
+ if(pack.prim_tri_index.size()) {
+ dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size());
+ device->tex_alloc("__prim_tri_index", dscene->prim_tri_index);
+ }
+ if(pack.prim_tri_verts.size()) {
+ dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size());
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
}
if(pack.prim_type.size()) {
dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size());
@@ -1273,7 +1354,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
- /* update normals */
+ /* Update normals. */
foreach(Mesh *mesh, scene->meshes) {
foreach(Shader *shader, mesh->used_shaders) {
if(shader->need_update_attributes)
@@ -1289,17 +1370,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
/* Update images needed for true displacement. */
- bool need_displacement_images = false;
+ bool true_displacement_used = false;
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->displacement_method != Mesh::DISPLACE_BUMP)
{
- need_displacement_images = true;
+ true_displacement_used = true;
break;
}
}
- if(need_displacement_images) {
+ if(true_displacement_used) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, dscene, scene, progress);
old_need_object_flags_update = scene->object_manager->need_flags_update;
@@ -1310,49 +1391,52 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
false);
}
- /* device update */
+ /* Device update. */
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
+ mesh_calc_offset(scene);
+ if(true_displacement_used) {
+ device_update_mesh(device, dscene, scene, true, progress);
+ }
if(progress.get_cancel()) return;
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;
- /* update displacement */
+ /* Update displacement. */
bool displacement_done = false;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && displace(device, dscene, scene, mesh, progress))
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ displace(device, dscene, scene, mesh, progress))
+ {
displacement_done = true;
+ }
+ }
- /* todo: properly handle cancel halfway displacement */
+ /* TODO: properly handle cancel halfway displacement */
if(progress.get_cancel()) return;
- /* device re-update after displacement */
+ /* Device re-update after displacement. */
if(displacement_done) {
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
- if(progress.get_cancel()) return;
-
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;
}
- /* update bvh */
+ /* Update bvh. */
size_t i = 0, num_bvh = 0;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && mesh->need_build_bvh())
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update && mesh->need_build_bvh()) {
num_bvh++;
-
+ }
+ }
TaskPool pool;
-
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
pool.push(function_bind(&Mesh::compute_bvh,
mesh,
+ dscene,
&scene->params,
&progress,
i,
@@ -1362,14 +1446,14 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
}
}
-
TaskPool::Summary summary;
pool.wait_work(&summary);
VLOG(2) << "Objects BVH build pool statistics:\n"
<< summary.full_report();
- foreach(Shader *shader, scene->shaders)
+ foreach(Shader *shader, scene->shaders) {
shader->need_update_attributes = false;
+ }
#ifdef __OBJECT_MOTION__
Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading);
@@ -1378,18 +1462,23 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool motion_blur = false;
#endif
- /* update obejcts */
+ /* Update objects. */
vector<Object *> volume_objects;
- foreach(Object *object, scene->objects)
+ foreach(Object *object, scene->objects) {
object->compute_bounds(motion_blur);
+ }
if(progress.get_cancel()) return;
device_update_bvh(device, dscene, scene, progress);
+ if(progress.get_cancel()) return;
+
+ device_update_mesh(device, dscene, scene, false, progress);
+ if(progress.get_cancel()) return;
need_update = false;
- if(need_displacement_images) {
+ if(true_displacement_used) {
/* Re-tag flags for update, so they're re-evaluated
* for meshes with correct bounding boxes.
*
@@ -1405,7 +1494,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->bvh_leaf_nodes);
device->tex_free(dscene->object_node);
- device->tex_free(dscene->tri_storage);
+ device->tex_free(dscene->prim_tri_verts);
+ device->tex_free(dscene->prim_tri_index);
device->tex_free(dscene->prim_type);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
@@ -1413,7 +1503,6 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tri_shader);
device->tex_free(dscene->tri_vnormal);
device->tex_free(dscene->tri_vindex);
- device->tex_free(dscene->tri_verts);
device->tex_free(dscene->curves);
device->tex_free(dscene->curve_keys);
device->tex_free(dscene->attributes_map);
@@ -1423,7 +1512,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
- dscene->tri_storage.clear();
+ dscene->prim_tri_verts.clear();
+ dscene->prim_tri_index.clear();
dscene->prim_type.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
@@ -1431,7 +1521,6 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->tri_shader.clear();
dscene->tri_vnormal.clear();
dscene->tri_vindex.clear();
- dscene->tri_verts.clear();
dscene->curves.clear();
dscene->curve_keys.clear();
dscene->attributes_map.clear();
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index edad6d32f00..0aea55544f2 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -72,7 +72,15 @@ public:
int num_segments() { return num_keys - 1; }
- void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform& aligned_space,
+ BoundBox& bounds) const;
};
Curve get_curve(size_t i) const
@@ -167,9 +175,16 @@ public:
void add_vertex_normals();
void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
- void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
+ void pack_verts(const vector<uint>& tri_prim_index,
+ uint4 *tri_vindex,
+ size_t vert_offset,
+ size_t tri_offset);
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
- void compute_bvh(SceneParams *params, Progress *progress, int n, int total);
+ void compute_bvh(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total);
bool need_attribute(Scene *scene, AttributeStandard std);
bool need_attribute(Scene *scene, ustring name);
@@ -213,15 +228,41 @@ public:
void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
+
+protected:
+ /* Calculate verts/triangles/curves offsets in global arrays. */
+ void mesh_calc_offset(Scene *scene);
+
+ void device_update_object(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_mesh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ bool for_displacement,
+ Progress& progress);
+
+ void device_update_attributes(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_bvh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_displacement_images(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 87020823df9..15b55d17301 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -611,10 +611,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma)
static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
{
/*
- * We re-use the SunSky struct of the new model, to avoid extra variables
- * zenith_Y/x/y is now radiance_x/y/z
- * perez_Y/x/y is now config_x/y/z
- */
+ * We re-use the SunSky struct of the new model, to avoid extra variables
+ * zenith_Y/x/y is now radiance_x/y/z
+ * perez_Y/x/y is now config_x/y/z
+ */
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
@@ -1596,7 +1596,7 @@ void RGBToBWNode::compile(SVMCompiler& compiler)
void RGBToBWNode::compile(OSLCompiler& compiler)
{
- compiler.add(this, "node_convert_from_color");
+ compiler.add(this, "node_rgb_to_bw");
}
/* Convert */
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index b821e2b6475..925e84ad96d 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -63,7 +63,8 @@ public:
device_vector<float4> bvh_nodes;
device_vector<float4> bvh_leaf_nodes;
device_vector<uint> object_node;
- device_vector<float4> tri_storage;
+ device_vector<uint> prim_tri_index;
+ device_vector<float4> prim_tri_verts;
device_vector<uint> prim_type;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
@@ -72,8 +73,7 @@ public:
/* mesh */
device_vector<uint> tri_shader;
device_vector<float4> tri_vnormal;
- device_vector<float4> tri_vindex;
- device_vector<float4> tri_verts;
+ device_vector<uint4> tri_vindex;
device_vector<float4> curves;
device_vector<float4> curve_keys;
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
index cef5adc0a61..599222da9c5 100644
--- a/intern/cycles/util/util_boundbox.h
+++ b/intern/cycles/util/util_boundbox.h
@@ -151,7 +151,7 @@ public:
(isfinite(max.x) && isfinite(max.y) && isfinite(max.z));
}
- BoundBox transformed(const Transform *tfm)
+ BoundBox transformed(const Transform *tfm) const
{
BoundBox result = BoundBox::empty;
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index f01db64a79b..6fed18a3db8 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -127,6 +127,19 @@ ccl_device_inline Transform make_transform(float a, float b, float c, float d,
return t;
}
+/* Constructs a coordinate frame from a normalized normal. */
+ccl_device_inline Transform make_transform_frame(float3 N)
+{
+ const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
+ const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
+ const float3 dx = normalize((dot(dx0,dx0) > dot(dx1,dx1))? dx0: dx1);
+ const float3 dy = normalize(cross(N, dx));
+ return make_transform(dx.x, dx.y, dx.z, 0.0f,
+ dy.x, dy.y, dy.z, 0.0f,
+ N.x , N.y, N.z, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+}
+
#ifndef __KERNEL_GPU__
ccl_device_inline Transform operator*(const Transform a, const Transform b)
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index 972befa185b..257c6ad7491 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -37,6 +37,7 @@
#define ccl_device_noinline static
#define ccl_global
#define ccl_constant
+#define ccl_restrict __restrict
#define __KERNEL_WITH_SSE_ALIGN__
#if defined(_WIN32) && !defined(FREE_WINDOWS)
diff --git a/intern/decklink/DeckLinkAPI.cpp b/intern/decklink/DeckLinkAPI.cpp
index 73a1264176b..aff25af70eb 100644
--- a/intern/decklink/DeckLinkAPI.cpp
+++ b/intern/decklink/DeckLinkAPI.cpp
@@ -15,19 +15,19 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file decklink/DeckLinkAPI.cpp
-* \ingroup decklink
-*/
+ * \ingroup decklink
+ */
#include "DeckLinkAPI.h"
diff --git a/intern/decklink/DeckLinkAPI.h b/intern/decklink/DeckLinkAPI.h
index f6d2b79f53e..2a429c18c3c 100644
--- a/intern/decklink/DeckLinkAPI.h
+++ b/intern/decklink/DeckLinkAPI.h
@@ -15,19 +15,19 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file decklink/DeckLinkAPI.h
-* \ingroup decklink
-*/
+ * \ingroup decklink
+ */
#ifndef __DECKLINKAPI_H__
#define __DECKLINKAPI_H__
diff --git a/intern/gpudirect/dvpapi.cpp b/intern/gpudirect/dvpapi.cpp
index 8ae5cdbf17b..56b58e0a348 100644
--- a/intern/gpudirect/dvpapi.cpp
+++ b/intern/gpudirect/dvpapi.cpp
@@ -1,33 +1,33 @@
/*
-* ***** 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
-*
-* ***** END GPL LICENSE BLOCK *****
-*/
+ * ***** 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) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
/** \file gpudirect/dvpapi.c
-* \ingroup gpudirect
-*/
+ * \ingroup gpudirect
+ */
#ifdef WIN32
diff --git a/intern/gpudirect/dvpapi.h b/intern/gpudirect/dvpapi.h
index 4cc259f0fe8..cafc4e862ae 100644
--- a/intern/gpudirect/dvpapi.h
+++ b/intern/gpudirect/dvpapi.h
@@ -1,33 +1,33 @@
/*
-* ***** 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
-*
-* ***** END GPL LICENSE BLOCK *****
-*/
+ * ***** 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) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
/** \file gpudirect/dvpapi.h
-* \ingroup gpudirect
-*/
+ * \ingroup gpudirect
+ */
#ifndef __DVPAPI_H__
#define __DVPAPI_H__
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index b89890a223c..6356da216b1 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -685,6 +685,91 @@ class ClearAllRestrictRender(Operator):
return {'FINISHED'}
+class TransformsToDeltas(Operator):
+ """Convert normal object transforms to delta transforms, """ \
+ """any existing delta transforms will be included as well"""
+ bl_idname = "object.transforms_to_deltas"
+ bl_label = "Transforms to Deltas"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ mode = EnumProperty(
+ items=(('ALL',
+ "All Transforms",
+ "Transfer location, rotation, and scale transforms",
+ ),
+ ('LOC',
+ "Location",
+ "Transfer location transforms only",
+ ),
+ ('ROT',
+ "Rotation",
+ "Transfer rotation transforms only",
+ ),
+ ('SCALE',
+ "Scale",
+ "Transfer scale transforms only",
+ ),
+ ),
+ name="Mode",
+ description="Which transforms to transfer",
+ default='ALL',
+ )
+ reset_values = BoolProperty(
+ name="Reset Values",
+ description=("Clear transform values after transferring to deltas"),
+ default=True,
+ )
+
+ @classmethod
+ def poll(cls, context):
+ obs = context.selected_editable_objects
+ return (obs is not None)
+
+ def execute(self, context):
+ for obj in context.selected_editable_objects:
+ if self.mode in {'ALL', 'LOC'}:
+ self.transfer_location(obj)
+
+ if self.mode in {'ALL', 'ROT'}:
+ self.transfer_rotation(obj)
+
+ if self.mode in {'ALL', 'SCALE'}:
+ self.transfer_scale(obj)
+
+ return {'FINISHED'}
+
+ def transfer_location(self, obj):
+ obj.delta_location += obj.location
+
+ if self.reset_values:
+ obj.location.zero()
+
+ def transfer_rotation(self, obj):
+ # TODO: add transforms together...
+ if obj.rotation_mode == 'QUATERNION':
+ obj.delta_rotation_quaternion += obj.rotation_quaternion
+
+ if self.reset_values:
+ obj.rotation_quaternion.identity()
+ elif obj.rotation_mode == 'AXIS_ANGLE':
+ pass # Unsupported
+ else:
+ delta = obj.delta_rotation_euler.copy()
+ obj.delta_rotation_euler = obj.rotation_euler
+ obj.delta_rotation_euler.rotate(delta)
+
+ if self.reset_values:
+ obj.rotation_euler.zero()
+
+ def transfer_scale(self, obj):
+ obj.delta_scale[0] *= obj.scale[0]
+ obj.delta_scale[1] *= obj.scale[1]
+ obj.delta_scale[2] *= obj.scale[2]
+
+ if self.reset_values:
+ obj.scale[:] = (1, 1, 1)
+
+
class TransformsToDeltasAnim(Operator):
"""Convert object animation for normal transforms to delta transforms"""
bl_idname = "object.anim_transforms_to_deltas"
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 2a98303d00e..4ca2f773dcc 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -96,25 +96,25 @@ class ConstraintButtonsPanel:
def CHILD_OF(self, context, layout, con):
self.target_template(layout, con)
- #split = layout.split()
-
- #col = split.column()
- #col.label(text="Location:")
- #col.prop(con, "use_location_x", text="X")
- #col.prop(con, "use_location_y", text="Y")
- #col.prop(con, "use_location_z", text="Z")
-
- #col = split.column()
- #col.label(text="Rotation:")
- #col.prop(con, "use_rotation_x", text="X")
- #col.prop(con, "use_rotation_y", text="Y")
- #col.prop(con, "use_rotation_z", text="Z")
-
- #col = split.column()
- #col.label(text="Scale:")
- #col.prop(con, "use_scale_x", text="X")
- #col.prop(con, "use_scale_y", text="Y")
- #col.prop(con, "use_scale_z", text="Z")
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Location:")
+ col.prop(con, "use_location_x", text="X")
+ col.prop(con, "use_location_y", text="Y")
+ col.prop(con, "use_location_z", text="Z")
+
+ col = split.column()
+ col.label(text="Rotation:")
+ col.prop(con, "use_rotation_x", text="X")
+ col.prop(con, "use_rotation_y", text="Y")
+ col.prop(con, "use_rotation_z", text="Z")
+
+ col = split.column()
+ col.label(text="Scale:")
+ col.prop(con, "use_scale_x", text="X")
+ col.prop(con, "use_scale_y", text="Y")
+ col.prop(con, "use_scale_z", text="Z")
row = layout.row()
row.operator("constraint.childof_set_inverse")
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 8baad4ea0f2..300be708049 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -404,6 +404,7 @@ class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
col.prop(gs, "use_glsl_lights", text="Lights")
col.prop(gs, "use_glsl_shaders", text="Shaders")
col.prop(gs, "use_glsl_shadows", text="Shadows")
+ col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting")
col = split.column()
col.prop(gs, "use_glsl_ramps", text="Ramps")
@@ -599,9 +600,35 @@ class WORLD_PT_game_world(WorldButtonsPanel, Panel):
row = layout.row()
row.column().prop(world, "horizon_color")
+ row.column().prop(world, "zenith_color")
row.column().prop(world, "ambient_color")
+class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel):
+ bl_label = "Environment Lighting"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ light = context.world.light_settings
+ self.layout.prop(light, "use_environment_light", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.world.light_settings
+
+ layout.active = light.use_environment_light
+
+ split = layout.split()
+ split.prop(light, "environment_energy", text="Energy")
+ split.prop(light, "environment_color", text="")
+
+
class WORLD_PT_game_mist(WorldButtonsPanel, Panel):
bl_label = "Mist"
COMPAT_ENGINES = {'BLENDER_GAME'}
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 4ea1c3a5cc7..794ef5189d6 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -193,7 +193,6 @@ class RENDER_PT_antialiasing(RenderButtonsPanel, Panel):
col = split.column()
col.row().prop(rd, "antialiasing_samples", expand=True)
sub = col.row()
- sub.enabled = not rd.use_border
sub.prop(rd, "use_full_sample")
col = split.column()
@@ -280,7 +279,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel):
col = split.column()
col.label(text="Memory:")
sub = col.column()
- sub.enabled = not (rd.use_border or rd.use_full_sample)
+ sub.enabled = not rd.use_full_sample
sub.prop(rd, "use_save_buffers")
sub = col.column()
sub.active = rd.use_compositing
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index e6f81656e45..6878d4dbb12 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -99,6 +99,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
if bpy.data.grease_pencil:
row.prop(dopesheet, "show_gpencil", text="")
+ layout.prop(dopesheet, "use_datablock_sort", text="")
#######################################
# DopeSheet Editor - General/Standard UI
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index f6f010e3760..8fbf9bfc6ac 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -77,6 +77,7 @@ class NLA_MT_view(Menu):
layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_curves")
+ layout.prop(st, "show_local_markers")
layout.separator()
layout.operator("anim.previewrange_set")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 247c3e099a0..882c3e82001 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -293,10 +293,6 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
layout.operator("object.randomize_transform")
layout.operator("object.align")
- layout.separator()
-
- layout.operator("object.anim_transforms_to_deltas")
-
# Armature EditMode extensions to Transform menu
class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
@@ -1476,6 +1472,15 @@ class VIEW3D_MT_object_apply(Menu):
props.location, props.rotation, props.scale = False, True, True
layout.separator()
+
+ layout.operator("object.transforms_to_deltas", text="Location to Deltas", text_ctxt=i18n_contexts.default).mode = 'LOC'
+ layout.operator("object.transforms_to_deltas", text="Rotation to Deltas", text_ctxt=i18n_contexts.default).mode = 'ROT'
+ layout.operator("object.transforms_to_deltas", text="Scale to Deltas", text_ctxt=i18n_contexts.default).mode = 'SCALE'
+
+ layout.operator("object.transforms_to_deltas", text="All Transforms to Deltas", text_ctxt=i18n_contexts.default).mode = 'ALL'
+ layout.operator("object.anim_transforms_to_deltas")
+
+ layout.separator()
layout.operator("object.visual_transform_apply", text="Visual Transform", text_ctxt=i18n_contexts.default)
layout.operator("object.duplicates_make_real")
@@ -2476,6 +2481,7 @@ class VIEW3D_MT_edit_mesh_clean(Menu):
layout.separator()
+ layout.operator("mesh.decimate")
layout.operator("mesh.dissolve_degenerate")
layout.operator("mesh.dissolve_limited")
layout.operator("mesh.face_make_planar")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index ce605fcdbbe..b2b4d4fa148 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1507,6 +1507,15 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
+ def draw_header(self, context):
+ layout = self.layout
+ layout.operator(
+ "sculpt.dynamic_topology_toggle",
+ icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
+ text="",
+ emboss=False,
+ )
+
def draw(self, context):
layout = self.layout
@@ -1515,11 +1524,6 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
- if context.sculpt_object.use_dynamic_topology_sculpting:
- layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dyntopo")
- else:
- layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dyntopo")
-
col = layout.column()
col.active = context.sculpt_object.use_dynamic_topology_sculpting
sub = col.column(align=True)
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index cb282b46bec..5874f95502b 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -58,13 +58,12 @@ extern "C" {
struct bAction *add_empty_action(struct Main *bmain, const char name[]);
/* Allocate a copy of the given Action and all its data */
-struct bAction *BKE_action_copy(struct bAction *src);
+struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src);
/* Deallocate all of the Action's data, but not the Action itself */
void BKE_action_free(struct bAction *act);
-// XXX is this needed?
-void BKE_action_make_local(struct bAction *act);
+void BKE_action_make_local(struct Main *bmain, struct bAction *act);
/* Action API ----------------- */
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 772e08589c1..983f3ce22b8 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -50,7 +50,8 @@ struct AnimMapper;
/* AnimData API */
/* Check if the given ID-block can have AnimData */
-bool id_type_can_have_animdata(struct ID *id);
+bool id_type_can_have_animdata(const short id_type);
+bool id_can_have_animdata(const struct ID *id);
/* Get AnimData from the given ID-block */
struct AnimData *BKE_animdata_from_id(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index cc082c084ce..326c335338f 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -76,8 +76,8 @@ struct bArmature *BKE_armature_from_object(struct Object *ob);
int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
-void BKE_armature_make_local(struct bArmature *arm);
-struct bArmature *BKE_armature_copy(struct bArmature *arm);
+void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm);
+struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index c663458963c..c7116bf2ef6 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -44,8 +44,8 @@ void BKE_brush_system_exit(void);
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
-struct Brush *BKE_brush_copy(struct Brush *brush);
-void BKE_brush_make_local(struct Brush *brush);
+struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush);
+void BKE_brush_make_local(struct Main *bmain, struct Brush *brush);
void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 7ec91b006b2..07db2217bac 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -46,8 +46,8 @@ struct MFace;
typedef struct LinkNode BVHCache;
/**
-* struct that kepts basic information about a BVHTree build from a editmesh
-*/
+ * struct that kepts basic information about a BVHTree build from a editmesh
+ */
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
@@ -122,6 +122,14 @@ BVHTree *bvhtree_from_mesh_verts_ex(
const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_edges(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_edges_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis);
+
BVHTree *bvhtree_from_mesh_edges(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
float epsilon, int tree_type, int axis);
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index d13a711c589..97f4b30894b 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -52,8 +52,8 @@ struct GPUFXSettings;
void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
-struct Camera *BKE_camera_copy(struct Camera *cam);
-void BKE_camera_make_local(struct Camera *cam);
+struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam);
+void BKE_camera_make_local(struct Main *bmain, struct Camera *cam);
void BKE_camera_free(struct Camera *ca);
/* Camera Usage */
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 23b3128f328..89dbe246910 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -70,8 +70,8 @@ void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
-struct Curve *BKE_curve_copy(struct Curve *cu);
-void BKE_curve_make_local(struct Curve *cu);
+struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu);
+void BKE_curve_make_local(struct Main *bmain, struct Curve *cu);
short BKE_curve_type_get(struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
void BKE_curve_curve_dimension_update(struct Curve *cu);
@@ -150,6 +150,16 @@ void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3
void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride);
+unsigned int BKE_curve_calc_coords_axis_len(
+ const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint);
+void BKE_curve_calc_coords_axis(
+ const struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint,
+ /* array params */
+ const unsigned int axis, const unsigned int stride,
+ float *r_points);
+
void BKE_nurb_knot_calc_u(struct Nurb *nu);
void BKE_nurb_knot_calc_v(struct Nurb *nu);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 26a40597ca8..5ef5a807f63 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -178,6 +178,7 @@ enum {
#define G_FILE_MESH_COMPAT (1 << 26)
/* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */
#define G_FILE_SAVE_COPY (1 << 27)
+#define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28)
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 24e330d927f..6159531d8bd 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -36,6 +36,7 @@ struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct Main;
/* ------------ Grease-Pencil API ------------------ */
@@ -53,7 +54,7 @@ struct bGPdata *gpencil_data_addnew(const char name[]);
struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
-struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy);
+struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index ae6e52b613b..4f2c89070cb 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -42,7 +42,7 @@ struct Scene;
void BKE_group_free(struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
-struct Group *BKE_group_copy(struct Group *group);
+struct Group *BKE_group_copy(struct Main *bmain, struct Group *group);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index eb98268c9f0..0895feef983 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char
void BKE_image_de_interlace(struct Image *ima, int odd);
-void BKE_image_make_local(struct Image *ima);
+void BKE_image_make_local(struct Main *bmain, struct Image *ima);
void BKE_image_tag_time(struct Image *ima);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 1edbb455ca4..f30f9eac4e8 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -39,6 +39,7 @@ struct ListBase;
struct Curve;
struct Object;
struct Lattice;
+struct Main;
struct Mesh;
struct WeightsArrayCache;
@@ -50,9 +51,9 @@ extern "C" {
void BKE_key_free(struct Key *sc);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
-struct Key *BKE_key_copy(struct Key *key);
+struct Key *BKE_key_copy(struct Main *bmain, struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
-void BKE_key_make_local(struct Key *key);
+void BKE_key_make_local(struct Main *bmain, struct Key *key);
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index d830c19651f..49b43550e67 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -44,9 +44,9 @@ struct Scene;
void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
-struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
+struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
-void BKE_lamp_make_local(struct Lamp *la);
+void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la);
void BKE_lamp_free(struct Lamp *la);
void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 828a40de1c9..606df9dcec8 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -47,9 +47,9 @@ struct MDeformVert;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
-struct Lattice *BKE_lattice_copy(struct Lattice *lt);
+struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt);
void BKE_lattice_free(struct Lattice *lt);
-void BKE_lattice_make_local(struct Lattice *lt);
+void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
struct LatticeDeformData;
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 2e225775af0..cb39b2e53ee 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -52,9 +52,8 @@ struct PropertyRNA;
void *BKE_libblock_alloc_notest(short type);
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_init_empty(struct ID *id);
-void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
-void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
void BKE_libblock_relink(struct ID *id);
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
@@ -81,10 +80,11 @@ void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
-bool id_make_local(struct ID *id, bool test);
+bool id_make_local(struct Main *bmain, struct ID *id, bool test);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
-bool id_copy(struct ID *id, struct ID **newid, bool test);
+bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
+void BKE_id_expand_local(struct ID *id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index c89dce99caa..c5f575c8c0f 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -41,6 +41,12 @@ enum {
IDWALK_NEVER_SELF = (1 << 1),
/**
+ * Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage.
+ * \note Object proxies are half-local, half-linked...
+ */
+ IDWALK_INDIRECT_USAGE = (1 << 2),
+
+ /**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
*/
@@ -53,7 +59,7 @@ enum {
enum {
IDWALK_RET_NOP = 0,
- IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */
+ IDWALK_RET_STOP_ITER = 1 << 0, /* Completly stop iteration. */
IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */
};
@@ -76,4 +82,10 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
+bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used);
+
+bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
+bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
+void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
+
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index e85a3e60751..e974b79ee66 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -56,9 +56,13 @@ void BKE_libblock_remap(
struct Main *bmain, void *old_idv, void *new_idv,
const short remap_flags) ATTR_NONNULL(1, 2);
-void BKE_libblock_unlink(struct Main *bmain, void *idv, const bool do_flag_never_null) ATTR_NONNULL();
+void BKE_libblock_unlink(
+ struct Main *bmain, void *idv,
+ const bool do_flag_never_null, const bool do_skip_indirect) ATTR_NONNULL();
-void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) ATTR_NONNULL(1);
+void BKE_libblock_relink_ex(
+ struct Main *bmain, void *idv, void *old_idv, void *new_idv,
+ const bool us_min_never_null) ATTR_NONNULL(1, 2);
typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
@@ -73,4 +77,4 @@ void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor
}
#endif
-#endif /* __BKE_LIBRARY_REMAP_H__ */ \ No newline at end of file
+#endif /* __BKE_LIBRARY_REMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index f3d12b5a8cc..97bfd0f3f07 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -123,7 +123,7 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask
/* general */
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
struct Mask *BKE_mask_copy_nolib(struct Mask *mask);
-struct Mask *BKE_mask_copy(struct Mask *mask);
+struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask);
void BKE_mask_free(struct Mask *mask);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 852564c8d90..0bc54ee4a16 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -47,17 +47,17 @@ struct Scene;
void init_def_material(void);
void BKE_material_free(struct Material *ma);
void BKE_material_free_ex(struct Material *ma, bool do_id_user);
-void test_object_materials(struct Main *bmain, struct ID *id);
+void test_object_materials(struct Object *ob, struct ID *id);
+void test_all_objects_materials(struct Main *bmain, struct ID *id);
void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
-struct Material *BKE_material_copy(struct Material *ma);
+struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma);
struct Material *localize_material(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
-void BKE_material_make_local(struct Material *ma);
-void extern_local_matarar(struct Material **matar, short totcol);
+void BKE_material_make_local(struct Main *bmain, struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index b8258455c65..42704c1b2db 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,9 +41,9 @@ struct MetaElem;
void BKE_mball_free(struct MetaBall *mb);
void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
-struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
+struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb);
-void BKE_mball_make_local(struct MetaBall *mb);
+void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 9330f41d19a..d3bb34d7a41 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -32,6 +32,7 @@
*/
struct ID;
+struct BMeshCreateParams;
struct BoundBox;
struct EdgeHash;
struct ListBase;
@@ -69,7 +70,9 @@ extern "C" {
/* *** mesh.c *** */
-struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index);
+struct BMesh *BKE_mesh_to_bmesh(
+ struct Mesh *me, struct Object *ob,
+ const bool add_key_index, const struct BMeshCreateParams *params);
int poly_find_loop_from_vert(
const struct MPoly *poly,
@@ -84,12 +87,11 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
-struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me);
-struct Mesh *BKE_mesh_copy(struct Mesh *me);
+struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
-void BKE_mesh_make_local(struct Mesh *me);
+void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me);
void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_calc(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index bf198c9b86b..b44cb226f0d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -336,7 +336,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
-struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree);
+struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree);
void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user);
void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to);
/* node->id user count */
@@ -346,7 +346,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
-void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist);
+void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 612c758139a..2c4df9620c2 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -103,8 +103,8 @@ struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene)
struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
-struct Object *BKE_object_copy(struct Object *ob);
-void BKE_object_make_local(struct Object *ob);
+struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
+void BKE_object_make_local(struct Main *bmain, struct Object *ob);
bool BKE_object_is_libdata(struct Object *ob);
bool BKE_object_obdata_is_libdata(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index ccb7dc8e015..03af0b7d6c9 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -98,7 +98,7 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
-struct Scene *BKE_scene_copy(struct Scene *sce, int type);
+struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
struct Object *BKE_scene_camera_find(struct Scene *sc);
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index 5f30df1d6e3..89b948a2126 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -33,8 +33,8 @@ struct Speaker;
void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
-struct Speaker *BKE_speaker_copy(struct Speaker *spk);
-void BKE_speaker_make_local(struct Speaker *spk);
+struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
+void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk);
void BKE_speaker_free(struct Speaker *spk);
#endif
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 43378551449..52b1906a78b 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -68,10 +68,10 @@ void colorband_update_sort(struct ColorBand *coba);
void BKE_texture_free(struct Tex *tex);
void BKE_texture_default(struct Tex *tex);
-struct Tex *BKE_texture_copy(struct Tex *tex);
+struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
struct Tex *BKE_texture_localize(struct Tex *tex);
-void BKE_texture_make_local(struct Tex *tex);
+void BKE_texture_make_local(struct Main *bmain, struct Tex *tex);
void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index 0be61fe0229..da5cca09b27 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -39,9 +39,9 @@ struct World;
void BKE_world_free(struct World *sc);
void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
-struct World *BKE_world_copy(struct World *wrld);
+struct World *BKE_world_copy(struct Main *bmain, struct World *wrld);
struct World *localize_world(struct World *wrld);
-void BKE_world_make_local(struct World *wrld);
+void BKE_world_make_local(struct Main *bmain, struct World *wrld);
#endif
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 46ee8a4d888..f7ff1261c8a 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -59,6 +59,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -92,68 +94,34 @@ bAction *add_empty_action(Main *bmain, const char name[])
/* .................................. */
-/* temp data for BKE_action_make_local */
-typedef struct tMakeLocalActionContext {
- bAction *act; /* original action */
- bAction *act_new; /* new action */
-
- bool is_lib; /* some action users were libraries */
- bool is_local; /* some action users were not libraries */
-} tMakeLocalActionContext;
-
-/* helper function for BKE_action_make_local() - local/lib init step */
-static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr)
+// does copy_fcurve...
+void BKE_action_make_local(Main *bmain, bAction *act)
{
- tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
-
- if (adt->action == mlac->act) {
- if (id->lib) mlac->is_lib = true;
- else mlac->is_local = true;
- }
-}
+ bool is_local = false, is_lib = false;
-/* helper function for BKE_action_make_local() - change references */
-static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr)
-{
- tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
-
- if (adt->action == mlac->act) {
- if (id->lib == NULL) {
- adt->action = mlac->act_new;
-
- id_us_plus(&mlac->act_new->id);
- id_us_min(&mlac->act->id);
- }
- }
-}
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
-// does copy_fcurve...
-void BKE_action_make_local(bAction *act)
-{
- tMakeLocalActionContext mlac = {act, NULL, false, false};
- Main *bmain = G.main;
-
- if (act->id.lib == NULL)
- return;
-
- /* XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default */
- if ((act->id.flag & LIB_FAKEUSER) && (act->id.us <= 1)) {
- id_clear_lib_data(bmain, &act->id);
+ if (!ID_IS_LINKED_DATABLOCK(act)) {
return;
}
-
- BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac);
-
- if (mlac.is_local && mlac.is_lib == false) {
- id_clear_lib_data(bmain, &act->id);
- }
- else if (mlac.is_local && mlac.is_lib) {
- mlac.act_new = BKE_action_copy(act);
- mlac.act_new->id.us = 0;
- BKE_id_lib_local_paths(bmain, act->id.lib, &mlac.act_new->id);
+ BKE_library_ID_test_usages(bmain, act, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &act->id);
+ BKE_id_expand_local(&act->id);
+ }
+ else {
+ bAction *act_new = BKE_action_copy(bmain, act);
+
+ act_new->id.us = 0;
- BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac);
+ BKE_libblock_remap(bmain, act, act_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
}
}
@@ -176,7 +144,7 @@ void BKE_action_free(bAction *act)
/* .................................. */
-bAction *BKE_action_copy(bAction *src)
+bAction *BKE_action_copy(Main *bmain, bAction *src)
{
bAction *dst = NULL;
bActionGroup *dgrp, *sgrp;
@@ -184,7 +152,7 @@ bAction *BKE_action_copy(bAction *src)
if (src == NULL)
return NULL;
- dst = BKE_libblock_copy(&src->id);
+ dst = BKE_libblock_copy(bmain, &src->id);
/* duplicate the lists of groups and markers */
BLI_duplicatelist(&dst->groups, &src->groups);
@@ -213,8 +181,9 @@ bAction *BKE_action_copy(bAction *src)
}
}
- if (src->id.lib) {
- BKE_id_lib_local_paths(G.main, src->id.lib, &dst->id);
+ if (ID_IS_LINKED_DATABLOCK(src)) {
+ BKE_id_expand_local(&dst->id);
+ BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id);
}
return dst;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index b7e8bc62470..7f10f6833db 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -79,15 +79,11 @@
/* Getter/Setter -------------------------------------------- */
/* Check if ID can have AnimData */
-bool id_type_can_have_animdata(ID *id)
+bool id_type_can_have_animdata(const short id_type)
{
- /* sanity check */
- if (id == NULL)
- return false;
-
/* Only some ID-blocks have this info for now */
/* TODO: finish adding this for the other blocktypes */
- switch (GS(id->name)) {
+ switch (id_type) {
/* has AnimData */
case ID_OB:
case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT:
@@ -100,9 +96,7 @@ bool id_type_can_have_animdata(ID *id)
case ID_MC:
case ID_MSK:
case ID_GD:
- {
return true;
- }
/* no AnimData */
default:
@@ -110,6 +104,14 @@ bool id_type_can_have_animdata(ID *id)
}
}
+bool id_can_have_animdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL)
+ return false;
+
+ return id_type_can_have_animdata(GS(id->name));
+}
/* Get AnimData from the given ID-block. In order for this to work, we assume that
* the AnimData pointer is stored immediately after the given ID-block in the struct,
@@ -121,7 +123,7 @@ AnimData *BKE_animdata_from_id(ID *id)
* types that do to be of type IdAdtTemplate, and extract the
* AnimData that way
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
return iat->adt;
}
@@ -139,7 +141,7 @@ AnimData *BKE_animdata_add_id(ID *id)
* types that do to be of type IdAdtTemplate, and add the AnimData
* to it using the template
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
/* check if there's already AnimData, in which case, don't add */
@@ -220,7 +222,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
AnimData *adt = iat->adt;
@@ -265,8 +267,8 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
- dadt->action = BKE_action_copy(adt->action);
- dadt->tmpact = BKE_action_copy(adt->tmpact);
+ dadt->action = BKE_action_copy(G.main, adt->action);
+ dadt->tmpact = BKE_action_copy(G.main, adt->tmpact);
}
else {
id_us_plus((ID *)dadt->action);
@@ -310,11 +312,11 @@ void BKE_animdata_copy_id_action(ID *id)
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
- adt->action = BKE_action_copy(adt->action);
+ adt->action = BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
- adt->tmpact = BKE_action_copy(adt->tmpact);
+ adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
}
}
}
@@ -338,8 +340,8 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a
/* handle actions... */
if (action_mode == ADT_MERGECOPY_SRC_COPY) {
/* make a copy of the actions */
- dst->action = BKE_action_copy(src->action);
- dst->tmpact = BKE_action_copy(src->tmpact);
+ dst->action = BKE_action_copy(G.main, src->action);
+ dst->tmpact = BKE_action_copy(G.main, src->tmpact);
}
else if (action_mode == ADT_MERGECOPY_SRC_REF) {
/* make a reference to it */
@@ -397,8 +399,8 @@ static void make_local_strips(ListBase *strips)
NlaStrip *strip;
for (strip = strips->first; strip; strip = strip->next) {
- if (strip->act) BKE_action_make_local(strip->act);
- if (strip->remap && strip->remap->target) BKE_action_make_local(strip->remap->target);
+ if (strip->act) BKE_action_make_local(G.main, strip->act);
+ if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target);
make_local_strips(&strip->strips);
}
@@ -410,10 +412,10 @@ void BKE_animdata_make_local(AnimData *adt)
NlaTrack *nlt;
/* Actions - Active and Temp */
- if (adt->action) BKE_action_make_local(adt->action);
- if (adt->tmpact) BKE_action_make_local(adt->tmpact);
+ if (adt->action) BKE_action_make_local(G.main, adt->action);
+ if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact);
/* Remaps */
- if (adt->remap && adt->remap->target) BKE_action_make_local(adt->remap->target);
+ if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target);
/* Drivers */
/* TODO: need to remap the ID-targets too? */
@@ -1048,7 +1050,7 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
*/
NlaTrack *nlt;
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
AnimData *adt = iat->adt;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index b59618f46b2..5f564e1c4d2 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -67,6 +67,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -142,46 +144,32 @@ void BKE_armature_free(bArmature *arm)
}
}
-void BKE_armature_make_local(bArmature *arm)
+void BKE_armature_make_local(Main *bmain, bArmature *arm)
{
- Main *bmain = G.main;
bool is_local = false, is_lib = false;
- Object *ob;
- if (arm->id.lib == NULL)
- return;
- if (arm->id.us == 1) {
- id_clear_lib_data(bmain, &arm->id);
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if (!ID_IS_LINKED_DATABLOCK(arm)) {
return;
}
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == arm) {
- if (ob->id.lib)
- is_lib = true;
- else
- is_local = true;
- }
- }
+ BKE_library_ID_test_usages(bmain, arm, &is_local, &is_lib);
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &arm->id);
- }
- else if (is_local && is_lib) {
- bArmature *arm_new = BKE_armature_copy(arm);
- arm_new->id.us = 0;
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &arm->id);
+ BKE_id_expand_local(&arm->id);
+ }
+ else {
+ bArmature *arm_new = BKE_armature_copy(bmain, arm);
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, arm->id.lib, &arm_new->id);
+ arm_new->id.us = 0;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == arm) {
- if (ob->id.lib == NULL) {
- ob->data = arm_new;
- id_us_plus(&arm_new->id);
- id_us_min(&arm->id);
- }
- }
+ BKE_libblock_remap(bmain, arm, arm_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
@@ -208,13 +196,13 @@ static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone
}
}
-bArmature *BKE_armature_copy(bArmature *arm)
+bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
{
bArmature *newArm;
Bone *oldBone, *newBone;
Bone *newActBone = NULL;
- newArm = BKE_libblock_copy(&arm->id);
+ newArm = BKE_libblock_copy(bmain, &arm->id);
BLI_duplicatelist(&newArm->bonebase, &arm->bonebase);
/* Duplicate the childrens' lists */
@@ -231,8 +219,9 @@ bArmature *BKE_armature_copy(bArmature *arm)
newArm->act_edbone = NULL;
newArm->sketch = NULL;
- if (arm->id.lib) {
- BKE_id_lib_local_paths(G.main, arm->id.lib, &newArm->id);
+ if (ID_IS_LINKED_DATABLOCK(arm)) {
+ BKE_id_expand_local(&newArm->id);
+ BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id);
}
return newArm;
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 826bb12a912..ece17335fa0 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
- BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL);
+ BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL);
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index e338974eca6..f3ff0f253e5 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -423,7 +423,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) {
+ if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) {
return;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 44cacffb71f..20621feac6c 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -38,6 +38,8 @@
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
@@ -170,11 +172,11 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode)
return NULL;
}
-Brush *BKE_brush_copy(Brush *brush)
+Brush *BKE_brush_copy(Main *bmain, Brush *brush)
{
Brush *brushn;
- brushn = BKE_libblock_copy(&brush->id);
+ brushn = BKE_libblock_copy(bmain, &brush->id);
if (brush->mtex.tex)
id_us_plus((ID *)brush->mtex.tex);
@@ -195,8 +197,9 @@ Brush *BKE_brush_copy(Brush *brush)
/* enable fake user by default */
id_fake_user_set(&brush->id);
- if (brush->id.lib) {
- BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id);
+ if (ID_IS_LINKED_DATABLOCK(brush)) {
+ BKE_id_expand_local(&brushn->id);
+ BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id);
}
return brushn;
@@ -216,63 +219,40 @@ void BKE_brush_free(Brush *brush)
BKE_previewimg_free(&(brush->preview));
}
-static void extern_local_brush(Brush *brush)
-{
- id_lib_extern((ID *)brush->mtex.tex);
- id_lib_extern((ID *)brush->mask_mtex.tex);
- id_lib_extern((ID *)brush->clone.image);
- id_lib_extern((ID *)brush->toggle_brush);
- id_lib_extern((ID *)brush->paint_curve);
-}
-
-void BKE_brush_make_local(Brush *brush)
+void BKE_brush_make_local(Main *bmain, Brush *brush)
{
+ bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
- Main *bmain = G.main;
- Scene *scene;
- bool is_local = false, is_lib = false;
-
- if (brush->id.lib == NULL) return;
+ if (!ID_IS_LINKED_DATABLOCK(brush)) {
+ return;
+ }
if (brush->clone.image) {
- /* special case: ima always local immediately. Clone image should only
- * have one user anyway. */
- id_clear_lib_data(bmain, &brush->clone.image->id);
- extern_local_brush(brush);
+ /* Special case: ima always local immediately. Clone image should only have one user anyway. */
+ id_make_local(bmain, &brush->clone.image->id, false);
}
- for (scene = bmain->scene.first; scene && ELEM(0, is_lib, is_local); scene = scene->id.next) {
- if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) {
- if (scene->id.lib) is_lib = true;
- else is_local = true;
+ BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &brush->id);
+ BKE_id_expand_local(&brush->id);
+
+ /* enable fake user by default */
+ id_fake_user_set(&brush->id);
}
- }
+ else {
+ Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &brush->id);
- extern_local_brush(brush);
+ brush_new->id.us = 0;
- /* enable fake user by default */
- id_fake_user_set(&brush->id);
- }
- else if (is_local && is_lib) {
- Brush *brush_new = BKE_brush_copy(brush); /* Ensures FAKE_USER is set */
- id_us_min(&brush_new->id); /* Remove user added by standard BKE_libblock_copy(). */
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, brush->id.lib, &brush_new->id);
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) {
- if (scene->id.lib == NULL) {
- BKE_paint_brush_set(&scene->toolsettings->imapaint.paint, brush_new);
- }
- }
+ BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
@@ -469,6 +449,7 @@ void BKE_brush_curve_preset(Brush *b, int preset)
curvemapping_changed(b->curve, false);
}
+/* XXX Unused function. */
int BKE_brush_texture_set_nr(Brush *brush, int nr)
{
ID *idtest, *id = NULL;
@@ -477,7 +458,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1);
if (idtest == NULL) { /* new tex */
- if (id) idtest = (ID *)BKE_texture_copy((Tex *)id);
+ if (id) idtest = (ID *)BKE_texture_copy(G.main, (Tex *)id);
else idtest = (ID *)BKE_texture_add(G.main, "Tex");
id_us_min(idtest);
}
@@ -816,9 +797,7 @@ void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float c
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-
- size = (int)((float)size / U.pixelsize);
-
+
/* make sure range is sane */
CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS);
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index a3cfe3f80b4..264d87b86f3 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -590,6 +590,77 @@ BVHTree *bvhtree_from_mesh_verts_ex(
/** \name Edge Builder
* \{ */
+static BVHTree *bvhtree_from_editmesh_edges_create_tree(
+ float epsilon, int tree_type, int axis,
+ BMEditMesh *em, const int edges_num,
+ const BLI_bitmap *edges_mask, int edges_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
+ }
+ else {
+ edges_num_active = edges_num;
+ }
+
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ BMIter iter;
+ BMEdge *eed;
+ BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], eed->v1->co);
+ copy_v3_v3(co[1], eed->v2->co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+/* Builds a bvh tree where nodes are the edges of the given em */
+BVHTree *bvhtree_from_editmesh_edges_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ int edge_num = em->bm->totedge;
+
+ BVHTree *tree = bvhtree_from_editmesh_edges_create_tree(
+ epsilon, tree_type, axis,
+ em, edge_num, edges_mask, edges_num_active);
+
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL; /* TODO */
+ data->raycast_callback = NULL; /* TODO */
+ /* TODO: not urgent however since users currently define own callbacks */
+ data->nearest_to_ray_callback = NULL;
+ }
+
+ return tree;
+}
+BVHTree *bvhtree_from_editmesh_edges(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+}
+
/* Builds a bvh tree where nodes are the edges of the given dm */
BVHTree *bvhtree_from_mesh_edges(
BVHTreeFromMesh *data, DerivedMesh *dm,
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index eabee742327..ae7aac8b54f 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -49,6 +49,8 @@
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -91,64 +93,46 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-Camera *BKE_camera_copy(Camera *cam)
+Camera *BKE_camera_copy(Main *bmain, Camera *cam)
{
Camera *camn;
- camn = BKE_libblock_copy(&cam->id);
+ camn = BKE_libblock_copy(bmain, &cam->id);
- id_lib_extern((ID *)camn->dof_ob);
-
- if (cam->id.lib) {
- BKE_id_lib_local_paths(G.main, cam->id.lib, &camn->id);
+ if (ID_IS_LINKED_DATABLOCK(cam)) {
+ BKE_id_expand_local(&camn->id);
+ BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id);
}
return camn;
}
-void BKE_camera_make_local(Camera *cam)
+void BKE_camera_make_local(Main *bmain, Camera *cam)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (cam->id.lib == NULL) return;
- if (cam->id.us == 1) {
- id_clear_lib_data(bmain, &cam->id);
+
+ if (!ID_IS_LINKED_DATABLOCK(cam)) {
return;
}
-
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == cam) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &cam->id);
- }
- else if (is_local && is_lib) {
- Camera *cam_new = BKE_camera_copy(cam);
- cam_new->id.us = 0;
+ BKE_library_ID_test_usages(bmain, cam, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &cam->id);
+ BKE_id_expand_local(&cam->id);
+ }
+ else {
+ Camera *cam_new = BKE_camera_copy(bmain, cam);
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, cam->id.lib, &cam_new->id);
+ cam_new->id.us = 0;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == cam) {
- if (ob->id.lib == NULL) {
- ob->data = cam_new;
- id_us_plus(&cam_new->id);
- id_us_min(&cam->id);
- }
- }
+ BKE_libblock_remap(bmain, cam, cam_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index c1f1f0128f5..2932939b208 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1322,7 +1322,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
.cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
.bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
};
- ScopesUpdateDataChunk data_chunk = {0};
+ ScopesUpdateDataChunk data_chunk = {{0}};
INIT_MINMAX(data_chunk.min, data_chunk.max);
BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index a591d536b43..4c9ddd495e3 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -2195,7 +2195,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
}
else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
Object workob;
- bPose pose = {0};
+ bPose pose = {{0}};
bPoseChannel *pchan, *tchan;
/* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
@@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
{
- if (*idpoin && (*idpoin)->lib)
+ if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin))
id_lib_extern(*idpoin);
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index dec6ff22360..0e634e21ea3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -58,6 +58,8 @@
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_material.h"
@@ -172,12 +174,13 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
return cu;
}
-Curve *BKE_curve_copy(Curve *cu)
+Curve *BKE_curve_copy(Main *bmain, Curve *cu)
{
Curve *cun;
int a;
- cun = BKE_libblock_copy(&cu->id);
+ cun = BKE_libblock_copy(bmain, &cu->id);
+
BLI_listbase_clear(&cun->nurb);
BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb));
@@ -191,45 +194,29 @@ Curve *BKE_curve_copy(Curve *cu)
cun->tb = MEM_dupallocN(cu->tb);
cun->bb = MEM_dupallocN(cu->bb);
- cun->key = BKE_key_copy(cu->key);
- if (cun->key) cun->key->from = (ID *)cun;
+ if (cu->key) {
+ cun->key = BKE_key_copy(bmain, cu->key);
+ cun->key->from = (ID *)cun;
+ }
cun->editnurb = NULL;
cun->editfont = NULL;
-#if 0 // XXX old animation system
- /* single user ipo too */
- if (cun->ipo) cun->ipo = copy_ipo(cun->ipo);
-#endif // XXX old animation system
-
id_us_plus((ID *)cun->vfont);
id_us_plus((ID *)cun->vfontb);
id_us_plus((ID *)cun->vfonti);
id_us_plus((ID *)cun->vfontbi);
- if (cu->id.lib) {
- BKE_id_lib_local_paths(G.main, cu->id.lib, &cun->id);
+ if (ID_IS_LINKED_DATABLOCK(cu)) {
+ BKE_id_expand_local(&cun->id);
+ BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id);
}
return cun;
}
-static void extern_local_curve(Curve *cu)
-{
- id_lib_extern((ID *)cu->vfont);
- id_lib_extern((ID *)cu->vfontb);
- id_lib_extern((ID *)cu->vfonti);
- id_lib_extern((ID *)cu->vfontbi);
-
- if (cu->mat) {
- extern_local_matarar(cu->mat, cu->totcol);
- }
-}
-
-void BKE_curve_make_local(Curve *cu)
+void BKE_curve_make_local(Main *bmain, Curve *cu)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - when there are only lib users: don't do
@@ -237,40 +224,26 @@ void BKE_curve_make_local(Curve *cu)
* - mixed: do a copy
*/
- if (cu->id.lib == NULL)
- return;
-
- if (cu->id.us == 1) {
- id_clear_lib_data(bmain, &cu->id);
- extern_local_curve(cu);
+ if (!ID_IS_LINKED_DATABLOCK(cu)) {
return;
}
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == cu) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
+ BKE_library_ID_test_usages(bmain, cu, &is_local, &is_lib);
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &cu->id);
- extern_local_curve(cu);
- }
- else if (is_local && is_lib) {
- Curve *cu_new = BKE_curve_copy(cu);
- cu_new->id.us = 0;
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &cu->id);
+ if (cu->key) {
+ BKE_key_make_local(bmain, cu->key);
+ }
+ BKE_id_expand_local(&cu->id);
+ }
+ else {
+ Curve *cu_new = BKE_curve_copy(bmain, cu);
- BKE_id_lib_local_paths(bmain, cu->id.lib, &cu_new->id);
+ cu_new->id.us = 0;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == cu) {
- if (ob->id.lib == NULL) {
- ob->data = cu_new;
- id_us_plus(&cu_new->id);
- id_us_min(&cu->id);
- }
- }
+ BKE_libblock_remap(bmain, cu, cu_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
@@ -1384,6 +1357,71 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
MEM_freeN(basisu);
}
+/**
+ * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
+ */
+unsigned int BKE_curve_calc_coords_axis_len(
+ const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint)
+{
+ const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1);
+ const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
+ return points_len;
+}
+
+/**
+ * Calculate an array for the entire curve (cyclic or non-cyclic).
+ * \note Call for each axis.
+ *
+ * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
+ */
+void BKE_curve_calc_coords_axis(
+ const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint,
+ /* array params */
+ const unsigned int axis, const unsigned int stride,
+ float *r_points)
+{
+ const unsigned int points_len = BKE_curve_calc_coords_axis_len(
+ bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
+ float *r_points_offset = r_points;
+
+ const unsigned int resolu_stride = resolu * stride;
+ const unsigned int bezt_array_last = bezt_array_len - 1;
+
+ for (unsigned int i = 0; i < bezt_array_last; i++) {
+ const BezTriple *bezt_curr = &bezt_array[i];
+ const BezTriple *bezt_next = &bezt_array[i + 1];
+ BKE_curve_forward_diff_bezier(
+ bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis], bezt_next->vec[1][axis],
+ r_points_offset, (int)resolu, stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ }
+
+ if (is_cyclic) {
+ const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
+ const BezTriple *bezt_next = &bezt_array[0];
+ BKE_curve_forward_diff_bezier(
+ bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis], bezt_next->vec[1][axis],
+ r_points_offset, (int)resolu, stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ if (use_cyclic_duplicate_endpoint) {
+ *r_points_offset = *r_points;
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+ }
+ else {
+ float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+
+ BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ UNUSED_VARS_NDEBUG(points_len);
+}
+
/* forward differencing method for bezier curve */
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index d02041d6da8..82ea710b5b6 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2205,7 +2205,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
/* 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
+ * Checking 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).
@@ -3785,7 +3785,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
const float brush_radius = brush->paint_distance * surface->radius_scale;
int numOfVerts;
int ii;
- Bounds3D mesh_bb = {0};
+ Bounds3D mesh_bb = {{0}};
VolumeGrid *grid = bData->grid;
dm = CDDM_copy(brush->dm);
@@ -4475,7 +4475,7 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
/* 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. */
+ * much more efficient 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);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index af1bcd0c545..ac4f566dc62 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -49,6 +49,7 @@
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
+#include "BKE_main.h"
/* ************************************************** */
@@ -358,7 +359,7 @@ bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src)
}
/* make a copy of a given gpencil datablock */
-bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy)
+bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy)
{
bGPDlayer *gpl, *gpld;
bGPdata *dst;
@@ -374,7 +375,7 @@ bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy)
}
else {
/* make a copy when others use this */
- dst = BKE_libblock_copy(&src->id);
+ dst = BKE_libblock_copy(bmain, &src->id);
}
/* copy layers */
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 95c7730431a..5a51d4797bb 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -86,18 +86,19 @@ Group *BKE_group_add(Main *bmain, const char *name)
return group;
}
-Group *BKE_group_copy(Group *group)
+Group *BKE_group_copy(Main *bmain, Group *group)
{
Group *groupn;
- groupn = BKE_libblock_copy(&group->id);
+ groupn = BKE_libblock_copy(bmain, &group->id);
BLI_duplicatelist(&groupn->gobject, &group->gobject);
/* Do not copy group's preview (same behavior as for objects). */
groupn->preview = NULL;
- if (group->id.lib) {
- BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id);
+ if (ID_IS_LINKED_DATABLOCK(group)) {
+ BKE_id_expand_local(&groupn->id);
+ BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id);
}
return groupn;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 69384a70969..f6f38977402 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -72,6 +72,8 @@
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -457,25 +459,18 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
BLI_duplicatelist(&nima->views, &ima->views);
- if (ima->id.lib) {
+ nima->preview = BKE_previewimg_copy(ima->preview);
+
+ if (ID_IS_LINKED_DATABLOCK(ima)) {
+ BKE_id_expand_local(&nima->id);
BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
}
return nima;
}
-static void extern_local_image(Image *UNUSED(ima))
-{
- /* Nothing to do: images don't link to other IDs. This function exists to
- * match id_make_local pattern. */
-}
-
-void BKE_image_make_local(struct Image *ima)
+void BKE_image_make_local(Main *bmain, Image *ima)
{
- Main *bmain = G.main;
- Tex *tex;
- Brush *brush;
- Mesh *me;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
@@ -483,147 +478,23 @@ void BKE_image_make_local(struct Image *ima)
* - mixed: make copy
*/
- if (ima->id.lib == NULL) return;
-
- /* Can't take short cut here: must check meshes at least because of bogus
- * texface ID refs. - z0r */
-#if 0
- if (ima->id.us == 1) {
- id_clear_lib_data(bmain, &ima->id);
- extern_local_image(ima);
+ if (!ID_IS_LINKED_DATABLOCK(ima)) {
return;
}
-#endif
-
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->ima == ima) {
- if (tex->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- for (brush = bmain->brush.first; brush; brush = brush->id.next) {
- if (brush->clone.image == ima) {
- if (brush->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- for (me = bmain->mesh.first; me; me = me->id.next) {
- if (me->mtface) {
- MTFace *tface;
- int a, i;
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
+ BKE_library_ID_test_usages(bmain, ima, &is_local, &is_lib);
- for (a = 0; a < me->totface; a++, tface++) {
- if (tface->tpage == ima) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- }
- }
-
- if (me->mtpoly) {
- MTexPoly *mtpoly;
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- mtpoly = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, mtpoly++) {
- if (mtpoly->tpage == ima) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- }
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &ima->id);
+ BKE_id_expand_local(&ima->id);
}
+ else {
+ Image *ima_new = BKE_image_copy(bmain, ima);
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &ima->id);
- extern_local_image(ima);
- }
- else if (is_local && is_lib) {
- Image *ima_new = BKE_image_copy(bmain, ima);
-
- ima_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ima->id.lib, &ima_new->id);
-
- tex = bmain->tex.first;
- while (tex) {
- if (tex->id.lib == NULL) {
- if (tex->ima == ima) {
- tex->ima = ima_new;
- id_us_plus(&ima_new->id);
- id_us_min(&ima->id);
- }
- }
- tex = tex->id.next;
- }
- brush = bmain->brush.first;
- while (brush) {
- if (brush->id.lib == NULL) {
- if (brush->clone.image == ima) {
- brush->clone.image = ima_new;
- id_us_plus(&ima_new->id);
- id_us_min(&ima->id);
- }
- }
- brush = brush->id.next;
- }
- /* Transfer references in texfaces. Texfaces don't add to image ID
- * user count *unless* there are no other users. See
- * readfile.c:lib_link_mtface. */
- me = bmain->mesh.first;
- while (me) {
- if (me->mtface) {
- MTFace *tface;
- int a, i;
-
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++) {
- if (tface->tpage == ima) {
- tface->tpage = ima_new;
- id_us_ensure_real((ID *)ima_new);
- id_lib_extern((ID *)ima_new);
- }
- }
- }
- }
- }
-
- if (me->mtpoly) {
- MTexPoly *mtpoly;
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- mtpoly = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, mtpoly++) {
- if (mtpoly->tpage == ima) {
- mtpoly->tpage = ima_new;
- id_us_ensure_real((ID *)ima_new);
- id_lib_extern((ID *)ima_new);
- }
- }
- }
- }
- }
+ ima_new->id.us = 0;
- me = me->id.next;
+ BKE_libblock_remap(bmain, ima, ima_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 2517e2cc197..e59facd3c39 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -58,6 +58,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
@@ -149,14 +150,12 @@ Key *BKE_key_add(ID *id) /* common function */
return key;
}
-Key *BKE_key_copy(Key *key)
+Key *BKE_key_copy(Main *bmain, Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
- if (key == NULL) return NULL;
-
- keyn = BKE_libblock_copy(&key->id);
+ keyn = BKE_libblock_copy(bmain, &key->id);
BLI_duplicatelist(&keyn->block, &key->block);
@@ -171,22 +170,19 @@ Key *BKE_key_copy(Key *key)
kb = kb->next;
}
- if (key->id.lib) {
- BKE_id_lib_local_paths(G.main, key->id.lib, &keyn->id);
+ if (ID_IS_LINKED_DATABLOCK(key)) {
+ BKE_id_expand_local(&keyn->id);
+ BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id);
}
return keyn;
}
-
Key *BKE_key_copy_nolib(Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
- if (key == NULL)
- return NULL;
-
keyn = MEM_dupallocN(key);
keyn->adt = NULL;
@@ -207,17 +203,16 @@ Key *BKE_key_copy_nolib(Key *key)
return keyn;
}
-void BKE_key_make_local(Key *key)
+void BKE_key_make_local(Main *bmain, Key *key)
{
+ /* Note that here for now we simply just make it local...
+ * Sounds fishy behavior, but since skeys are not *real* IDs... */
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
- if (key == NULL) return;
-
- key->id.lib = NULL;
- new_id(NULL, &key->id, NULL);
+ if (!ID_IS_LINKED_DATABLOCK(key)) {
+ return;
+ }
+
+ id_clear_lib_data(bmain, &key->id);
}
/* Sort shape keys and Ipo curves after a change. This assumes that at most
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 692b703f721..003b154a70b 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -50,6 +50,8 @@
#include "BKE_global.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -114,12 +116,12 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
return la;
}
-Lamp *BKE_lamp_copy(Lamp *la)
+Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
{
Lamp *lan;
int a;
- lan = BKE_libblock_copy(&la->id);
+ lan = BKE_libblock_copy(bmain, &la->id);
for (a = 0; a < MAX_MTEX; a++) {
if (lan->mtex[a]) {
@@ -132,13 +134,13 @@ Lamp *BKE_lamp_copy(Lamp *la)
lan->curfalloff = curvemapping_copy(la->curfalloff);
if (la->nodetree)
- lan->nodetree = ntreeCopyTree(la->nodetree);
+ lan->nodetree = ntreeCopyTree(bmain, la->nodetree);
- if (la->preview)
- lan->preview = BKE_previewimg_copy(la->preview);
-
- if (la->id.lib) {
- BKE_id_lib_local_paths(G.main, la->id.lib, &lan->id);
+ lan->preview = BKE_previewimg_copy(la->preview);
+
+ if (ID_IS_LINKED_DATABLOCK(la)) {
+ BKE_id_expand_local(&lan->id);
+ BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id);
}
return lan;
@@ -166,14 +168,12 @@ Lamp *localize_lamp(Lamp *la)
lan->nodetree = ntreeLocalize(la->nodetree);
lan->preview = NULL;
-
+
return lan;
}
-void BKE_lamp_make_local(Lamp *la)
+void BKE_lamp_make_local(Main *bmain, Lamp *la)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
@@ -181,42 +181,23 @@ void BKE_lamp_make_local(Lamp *la)
* - mixed: make copy
*/
- if (la->id.lib == NULL) return;
- if (la->id.us == 1) {
- id_clear_lib_data(bmain, &la->id);
+ if (!ID_IS_LINKED_DATABLOCK(la)) {
return;
}
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == la) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
+
+ BKE_library_ID_test_usages(bmain, la, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &la->id);
+ BKE_id_expand_local(&la->id);
}
- ob = ob->id.next;
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &la->id);
- }
- else if (is_local && is_lib) {
- Lamp *la_new = BKE_lamp_copy(la);
- la_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, la->id.lib, &la_new->id);
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == la) {
-
- if (ob->id.lib == NULL) {
- ob->data = la_new;
- id_us_plus(&la_new->id);
- id_us_min(&la->id);
- }
- }
- ob = ob->id.next;
+ else {
+ Lamp *la_new = BKE_lamp_copy(bmain, la);
+
+ la_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, la, la_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 58c0a567116..67f49266efc 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -59,6 +59,8 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -275,15 +277,17 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
return lt;
}
-Lattice *BKE_lattice_copy(Lattice *lt)
+Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
{
Lattice *ltn;
- ltn = BKE_libblock_copy(&lt->id);
+ ltn = BKE_libblock_copy(bmain, &lt->id);
ltn->def = MEM_dupallocN(lt->def);
- ltn->key = BKE_key_copy(ltn->key);
- if (ltn->key) ltn->key->from = (ID *)ltn;
+ if (lt->key) {
+ ltn->key = BKE_key_copy(bmain, ltn->key);
+ ltn->key->from = (ID *)ltn;
+ }
if (lt->dvert) {
int tot = lt->pntsu * lt->pntsv * lt->pntsw;
@@ -293,8 +297,9 @@ Lattice *BKE_lattice_copy(Lattice *lt)
ltn->editlatt = NULL;
- if (lt->id.lib) {
- BKE_id_lib_local_paths(G.main, lt->id.lib, &ltn->id);
+ if (ID_IS_LINKED_DATABLOCK(lt)) {
+ BKE_id_expand_local(&ltn->id);
+ BKE_id_lib_local_paths(bmain, lt->id.lib, &ltn->id);
}
return ltn;
@@ -325,48 +330,35 @@ void BKE_lattice_free(Lattice *lt)
}
-void BKE_lattice_make_local(Lattice *lt)
+void BKE_lattice_make_local(Main *bmain, Lattice *lt)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (lt->id.lib == NULL) return;
- if (lt->id.us == 1) {
- id_clear_lib_data(bmain, &lt->id);
+
+ if (!ID_IS_LINKED_DATABLOCK(lt)) {
return;
}
-
- for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == lt) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &lt->id);
- }
- else if (is_local && is_lib) {
- Lattice *lt_new = BKE_lattice_copy(lt);
- lt_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, lt->id.lib, &lt_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == lt) {
- if (ob->id.lib == NULL) {
- ob->data = lt_new;
- id_us_plus(&lt_new->id);
- id_us_min(&lt->id);
- }
+
+ BKE_library_ID_test_usages(bmain, lt, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &lt->id);
+ if (lt->key) {
+ BKE_key_make_local(bmain, lt->key);
}
+ BKE_id_expand_local(&lt->id);
+ }
+ else {
+ Lattice *lt_new = BKE_lattice_copy(bmain, lt);
+
+ lt_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, lt, lt_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 5f7bded4262..978f1acefba 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -141,7 +141,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
void id_lib_extern(ID *id)
{
- if (id) {
+ if (id && ID_IS_LINKED_DATABLOCK(id)) {
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag -= LIB_TAG_INDIRECT;
@@ -250,9 +250,27 @@ void id_fake_user_clear(ID *id)
}
}
+static int id_expand_local_callback(
+ void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+{
+ if (*id_pointer) {
+ id_lib_extern(*id_pointer);
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
+ */
+void BKE_id_expand_local(ID *id)
+{
+ BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+}
+
/* calls the appropriate make_local method for the block, unless test. Returns true
* if the block can be made local. */
-bool id_make_local(ID *id, bool test)
+bool id_make_local(Main *bmain, ID *id, bool test)
{
if (id->tag & LIB_TAG_INDIRECT)
return false;
@@ -263,54 +281,45 @@ bool id_make_local(ID *id, bool test)
case ID_LI:
return false; /* can't be linked */
case ID_OB:
- if (!test) BKE_object_make_local((Object *)id);
+ if (!test) BKE_object_make_local(bmain, (Object *)id);
return true;
case ID_ME:
- if (!test) {
- BKE_mesh_make_local((Mesh *)id);
- BKE_key_make_local(((Mesh *)id)->key);
- }
+ if (!test) BKE_mesh_make_local(bmain, (Mesh *)id);
return true;
case ID_CU:
- if (!test) {
- BKE_curve_make_local((Curve *)id);
- BKE_key_make_local(((Curve *)id)->key);
- }
+ if (!test) BKE_curve_make_local(bmain, (Curve *)id);
return true;
case ID_MB:
- if (!test) BKE_mball_make_local((MetaBall *)id);
+ if (!test) BKE_mball_make_local(bmain, (MetaBall *)id);
return true;
case ID_MA:
- if (!test) BKE_material_make_local((Material *)id);
+ if (!test) BKE_material_make_local(bmain, (Material *)id);
return true;
case ID_TE:
- if (!test) BKE_texture_make_local((Tex *)id);
+ if (!test) BKE_texture_make_local(bmain, (Tex *)id);
return true;
case ID_IM:
- if (!test) BKE_image_make_local((Image *)id);
+ if (!test) BKE_image_make_local(bmain, (Image *)id);
return true;
case ID_LT:
- if (!test) {
- BKE_lattice_make_local((Lattice *)id);
- BKE_key_make_local(((Lattice *)id)->key);
- }
+ if (!test) BKE_lattice_make_local(bmain, (Lattice *)id);
return true;
case ID_LA:
- if (!test) BKE_lamp_make_local((Lamp *)id);
+ if (!test) BKE_lamp_make_local(bmain, (Lamp *)id);
return true;
case ID_CA:
- if (!test) BKE_camera_make_local((Camera *)id);
+ if (!test) BKE_camera_make_local(bmain, (Camera *)id);
return true;
case ID_SPK:
- if (!test) BKE_speaker_make_local((Speaker *)id);
+ if (!test) BKE_speaker_make_local(bmain, (Speaker *)id);
return true;
case ID_IP:
return false; /* deprecated */
case ID_KE:
- if (!test) BKE_key_make_local((Key *)id);
+ if (!test) BKE_key_make_local(bmain, (Key *)id);
return true;
case ID_WO:
- if (!test) BKE_world_make_local((World *)id);
+ if (!test) BKE_world_make_local(bmain, (World *)id);
return true;
case ID_SCR:
return false; /* can't be linked */
@@ -323,16 +332,16 @@ bool id_make_local(ID *id, bool test)
case ID_GR:
return false; /* not implemented */
case ID_AR:
- if (!test) BKE_armature_make_local((bArmature *)id);
+ if (!test) BKE_armature_make_local(bmain, (bArmature *)id);
return true;
case ID_AC:
- if (!test) BKE_action_make_local((bAction *)id);
+ if (!test) BKE_action_make_local(bmain, (bAction *)id);
return true;
case ID_NT:
- if (!test) ntreeMakeLocal((bNodeTree *)id, true);
+ if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true);
return true;
case ID_BR:
- if (!test) BKE_brush_make_local((Brush *)id);
+ if (!test) BKE_brush_make_local(bmain, (Brush *)id);
return true;
case ID_WM:
return false; /* can't be linked */
@@ -349,9 +358,11 @@ bool id_make_local(ID *id, bool test)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-bool id_copy(ID *id, ID **newid, bool test)
+bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
{
- if (!test) *newid = NULL;
+ if (!test) {
+ *newid = NULL;
+ }
/* conventions:
* - make shallow copy, only this ID block
@@ -362,80 +373,80 @@ bool id_copy(ID *id, ID **newid, bool test)
case ID_LI:
return false; /* can't be copied from here */
case ID_OB:
- if (!test) *newid = (ID *)BKE_object_copy((Object *)id);
+ if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
return true;
case ID_ME:
- if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id);
+ if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id);
return true;
case ID_CU:
- if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id);
+ if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id);
return true;
case ID_MB:
- if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id);
+ if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id);
return true;
case ID_MA:
- if (!test) *newid = (ID *)BKE_material_copy((Material *)id);
+ if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id);
return true;
case ID_TE:
- if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id);
+ if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id);
return true;
case ID_IM:
- if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id);
+ if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id);
return true;
case ID_LT:
- if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id);
+ if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id);
return true;
case ID_LA:
- if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id);
+ if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id);
return true;
case ID_SPK:
- if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id);
+ if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
return true;
case ID_CA:
- if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id);
+ if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
return true;
case ID_IP:
return false; /* deprecated */
case ID_KE:
- if (!test) *newid = (ID *)BKE_key_copy((Key *)id);
+ if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
return true;
case ID_WO:
- if (!test) *newid = (ID *)BKE_world_copy((World *)id);
+ if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
return true;
case ID_SCR:
return false; /* can't be copied from here */
case ID_VF:
return false; /* not implemented */
case ID_TXT:
- if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id);
+ if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
return true;
case ID_SO:
return false; /* not implemented */
case ID_GR:
- if (!test) *newid = (ID *)BKE_group_copy((Group *)id);
+ if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
return true;
case ID_AR:
- if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id);
+ if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id);
return true;
case ID_AC:
- if (!test) *newid = (ID *)BKE_action_copy((bAction *)id);
+ if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id);
return true;
case ID_NT:
- if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id);
+ if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id);
return true;
case ID_BR:
- if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id);
+ if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id);
return true;
case ID_WM:
return false; /* can't be copied from here */
case ID_GD:
- if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false);
+ if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false);
return true;
case ID_MSK:
- if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
+ if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
return true;
case ID_LS:
- if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
+ if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
return true;
}
@@ -450,7 +461,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (id) {
/* if property isn't editable, we're going to have an extra block hanging around until we save */
if (RNA_property_editable(ptr, prop)) {
- if (id_copy(id, &newid, false) && newid) {
+ if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
BKE_animdata_copy_id_action(id);
/* us is 1 by convention, but RNA_property_pointer_set
@@ -621,7 +632,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
@@ -969,7 +980,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action)
}
/* used everywhere in blenkernel */
-void *BKE_libblock_copy_ex(Main *bmain, ID *id)
+void *BKE_libblock_copy(Main *bmain, ID *id)
{
ID *idn;
size_t idn_len;
@@ -1021,11 +1032,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
return idn;
}
-void *BKE_libblock_copy(ID *id)
-{
- return BKE_libblock_copy_ex(G.main, id);
-}
-
static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
{
ID *id = *id_pointer;
@@ -1045,7 +1051,7 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i
void BKE_libblock_relink(ID *id)
{
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
return;
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
@@ -1259,7 +1265,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
for (idtest = lb->first; idtest; idtest = idtest->next) {
/* if idtest is not a lib */
- if (id != idtest && idtest->lib == NULL) {
+ if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
/* do not test alphabetic! */
/* optimized */
if (idtest->name[2] == name[0]) {
@@ -1319,7 +1325,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
if ( (id != idtest) &&
- (idtest->lib == NULL) &&
+ !ID_IS_LINKED_DATABLOCK(idtest) &&
(*name == *(idtest->name + 2)) &&
STREQLEN(name, idtest->name + 2, left_len) &&
(BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
@@ -1401,7 +1407,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
char name[MAX_ID_NAME - 2];
/* if library, don't rename */
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
return false;
/* if no libdata given, look up based on ID */
@@ -1465,7 +1471,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
ntree = ntreeFromID(id);
if (ntree) {
- ntreeMakeLocal(ntree, false);
+ ntreeMakeLocal(bmain, ntree, false);
}
if (GS(id->name) == ID_OB) {
@@ -1506,7 +1512,7 @@ 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
- if (id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(id)) {
/* datablocks that were indirectly related are now direct links
* without this, appending data that has a link to other data will fail to write */
if (lib && id->lib->parent == lib) {
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 7cb5bfd1360..b623cecb0ff 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -45,6 +45,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
@@ -71,6 +72,7 @@
#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_rigidbody.h"
#include "BKE_sca.h"
@@ -85,7 +87,7 @@
if (!((_data)->status & IDWALK_STOP)) { \
const int _flag = (_data)->flag; \
ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \
if (_flag & IDWALK_READONLY) { \
BLI_assert(*(id_pp) == old_id); \
} \
@@ -126,6 +128,7 @@ enum {
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
+ int cd_flag;
LibraryIDLinkCallback callback;
void *user_data;
int status;
@@ -285,6 +288,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
do {
data.self_id = id;
+ data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -400,7 +404,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
Object *object = (Object *) id;
+ /* Object is special, proxies make things hard... */
+ const int data_cd_flag = data.cd_flag;
+ const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0;
+
/* object data special case */
+ data.cd_flag |= proxy_cd_flag;
if (object->type == OB_EMPTY) {
/* empty can have NULL or Image */
CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
@@ -411,6 +420,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
}
}
+ data.cd_flag = data_cd_flag;
CALLBACK_INVOKE(object->parent, IDWALK_NOP);
CALLBACK_INVOKE(object->track, IDWALK_NOP);
@@ -419,9 +429,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+
+ data.cd_flag |= proxy_cd_flag;
for (i = 0; i < object->totcol; i++) {
CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
}
+ data.cd_flag = data_cd_flag;
+
CALLBACK_INVOKE(object->gpd, IDWALK_USER);
CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
@@ -433,10 +447,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (object->pose) {
bPoseChannel *pchan;
+
+ data.cd_flag |= proxy_cd_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
+ data.cd_flag = data_cd_flag;
}
if (object->rigidbody_constraint) {
@@ -468,6 +485,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (i = 0; i < mesh->totcol; i++) {
CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
}
+
+ /* XXX Really not happy with this - probably texface should rather use some kind of
+ * 'texture slots' and just set indices in each poly/face item - would also save some memory.
+ * Maybe a nice TODO for blender2.8? */
+ if (mesh->mtface || mesh->mtpoly) {
+ for (i = 0; i < mesh->pdata.totlayer; i++) {
+ if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
+
+ for (int j = 0; j < mesh->totpoly; j++, txface++) {
+ CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE);
+ }
+ }
+ }
+
+ for (i = 0; i < mesh->fdata.totlayer; i++) {
+ if (mesh->fdata.layers[i].type == CD_MTFACE) {
+ MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
+
+ for (int j = 0; j < mesh->totface; j++, tface++) {
+ CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE);
+ }
+ }
+ }
+ }
break;
}
@@ -743,6 +785,80 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
}
}
+/**
+ * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used.
+ */
+/* This is a 'simplified' abstract version of BKE_library_foreach_ID_link() above, quite useful to reduce
+ * useless ietrations in some cases. */
+bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+{
+ if (id_type_used == ID_AC) {
+ return id_type_can_have_animdata(id_type_owner);
+ }
+
+ switch (id_type_owner) {
+ case ID_LI:
+ return ELEM(id_type_used, ID_LI);
+ case ID_SCE:
+ return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
+ ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) ||
+ BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_OB:
+ /* Could be the following, but simpler to just always say 'yes' here. */
+#if 0
+ return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */
+ ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
+ /* + constraints, modifiers and game logic ID types... */);
+#else
+ return true;
+#endif
+ case ID_ME:
+ return ELEM(id_type_used, ID_ME, ID_KE, ID_MA);
+ case ID_CU:
+ return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
+ case ID_MB:
+ return ELEM(id_type_used, ID_MA);
+ case ID_MA:
+ return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_TE:
+ return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_LT:
+ return ELEM(id_type_used, ID_KE);
+ case ID_LA:
+ return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_CA:
+ return ELEM(id_type_used, ID_OB);
+ case ID_KE:
+ return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); /* Warning! key->from, could be more types in future? */
+ case ID_SCR:
+ return ELEM(id_type_used, ID_SCE);
+ case ID_WO:
+ return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_SPK:
+ return ELEM(id_type_used, ID_SO);
+ case ID_GR:
+ return ELEM(id_type_used, ID_OB);
+ case ID_NT:
+ /* Could be the following, but node.id has no type restriction... */
+#if 0
+ return ELEM(id_type_used, ID_GD /* + node.id types... */);
+#else
+ return true;
+#endif
+ case ID_BR:
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ case ID_MC:
+ return ELEM(id_type_used, ID_GD, ID_IM);
+ case ID_MSK:
+ return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
+ case ID_LS:
+ return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ default:
+ return false;
+ }
+}
+
+
/* ***** ID users iterator. ***** */
typedef struct IDUsersIter {
ID *id;
@@ -751,7 +867,7 @@ typedef struct IDUsersIter {
int lb_idx;
ID *curr_id;
- int count; /* Set by callback. */
+ int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
@@ -760,13 +876,17 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_i
if (*id_p && (*id_p == iter->id)) {
#if 0
- printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n",
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
- (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0);
-#else
- UNUSED_VARS(cb_flag);
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+ (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
#endif
- iter->count++;
+ if (cb_flag & IDWALK_INDIRECT_USAGE) {
+ iter->count_indirect++;
+ }
+ else {
+ iter->count_direct++;
+ }
}
return IDWALK_RET_NOP;
@@ -789,9 +909,86 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
/* We do not care about iter.lb_array/lb_idx here... */
iter.id = id_used;
iter.curr_id = id_user;
- iter.count = 0;
+ iter.count_direct = iter.count_indirect = 0;
BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
- return iter.count;
+ return iter.count_direct + iter.count_indirect;
+}
+
+static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
+{
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+
+ is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
+ }
+ }
+
+ return is_defined;
+}
+
+/**
+ * Check whether given ID is used locally (i.e. by another non-linked ID).
+ */
+bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
+{
+ return library_ID_is_used(bmain, idv, false);
+}
+
+/**
+ * Check whether given ID is used indirectly (i.e. by another linked ID).
+ */
+bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
+{
+ return library_ID_is_used(bmain, idv, true);
+}
+
+/**
+ * Combine \a BKE_library_ID_is_locally_used() and \a BKE_library_ID_is_indirectly_used() in a single call.
+ */
+void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
+{
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+
+ is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
+ }
+ }
+
+ *is_used_local = (iter.count_direct != 0);
+ *is_used_linked = (iter.count_indirect != 0);
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index e9598bee0df..62a6541529a 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -88,9 +88,11 @@
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_mball.h"
+#include "BKE_modifier.h"
#include "BKE_movieclip.h"
-#include "BKE_mask.h"
+#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -162,18 +164,22 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
}
if (*id_p && (*id_p == old_id)) {
- const bool is_indirect = (id->lib != NULL);
+ const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
* Edit Mode is also a 'skip direct' case. */
const bool is_obj = (GS(id->name) == ID_OB);
- const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+#ifdef DEBUG_PRINT
+ printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n",
+ id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
+#endif
+
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -181,13 +187,16 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
if ((is_never_null && skip_never_null) ||
(is_obj_editmode && (((Object *)id)->data == *id_p)) ||
- (skip_indirect && (is_proxy || is_indirect)))
+ (skip_indirect && is_indirect))
{
- if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) {
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ }
+ else if (is_never_null || is_obj_editmode) {
id_remap_data->skipped_direct++;
}
else {
- id_remap_data->skipped_indirect++;
+ BLI_assert(0);
}
if (cb_flag & IDWALK_USER) {
id_remap_data->skipped_refcounted++;
@@ -221,6 +230,145 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
return IDWALK_RET_NOP;
}
+/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */
+static void libblock_remap_data_preprocess_scene_base_unlink(
+ IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
+{
+ if (skip_indirect && is_indirect) {
+ r_id_remap_data->skipped_indirect++;
+ r_id_remap_data->skipped_refcounted++;
+ }
+ else {
+ id_us_min((ID *)base->object);
+ BKE_scene_base_unlink(sce, base);
+ MEM_freeN(base);
+ if (!is_indirect) {
+ r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+}
+
+static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
+{
+ switch (GS(r_id_remap_data->id->name)) {
+ case ID_SCE:
+ {
+ Scene *sce = (Scene *)r_id_remap_data->id;
+
+ if (!r_id_remap_data->new_id) {
+ const bool is_indirect = (sce->id.lib != NULL);
+ const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+
+ /* In case we are unlinking... */
+ if (!r_id_remap_data->old_id) {
+ /* ... everything from scene. */
+ Base *base, *base_next;
+ for (base = sce->base.first; base; base = base_next) {
+ base_next = base->next;
+ libblock_remap_data_preprocess_scene_base_unlink(
+ r_id_remap_data, sce, base, skip_indirect, is_indirect);
+ }
+ }
+ else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
+ /* ... a specific object from scene. */
+ Object *old_ob = (Object *)r_id_remap_data->old_id;
+ Base *base = BKE_scene_base_find(sce, old_ob);
+
+ if (base) {
+ libblock_remap_data_preprocess_scene_base_unlink(
+ r_id_remap_data, sce, base, skip_indirect, is_indirect);
+ }
+ }
+ }
+ break;
+ }
+ case ID_OB:
+ {
+ ID *old_id = r_id_remap_data->old_id;
+ if (!old_id || GS(old_id->name) == ID_AR) {
+ Object *ob = (Object *)r_id_remap_data->id;
+ /* Object's pose holds reference to armature bones... sic */
+ /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
+ * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
+ * another complex and risky condition nightmare like the one we have in
+ * foreach_libblock_remap_callback()... */
+ if (ob->pose && (!old_id || ob->data == old_id)) {
+ BLI_assert(ob->type == OB_ARMATURE);
+ ob->pose->flag |= POSE_RECALC;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob)
+{
+ if (old_ob->flag & OB_FROMGROUP) {
+ /* Note that for Scene's BaseObject->flag, either we:
+ * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
+ * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
+ * So in any case, no need to update them here. */
+ if (BKE_group_object_find(NULL, old_ob) == NULL) {
+ old_ob->flag &= ~OB_FROMGROUP;
+ }
+ if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
+ for (Group *group = bmain->group.first; group; group = group->id.next) {
+ BKE_group_object_unlink(group, NULL, NULL, NULL);
+ }
+ }
+ else {
+ new_ob->flag |= OB_FROMGROUP;
+ }
+ }
+}
+
+static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id)
+{
+ /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
+ * in one scene...). */
+ for (Base *base = sce->base.first; base; base = base->next) {
+ if (base->flag & OB_FROMGROUP) {
+ Object *ob = base->object;
+
+ if (ob->flag & OB_FROMGROUP) {
+ Group *grp = BKE_group_object_find(NULL, ob);
+
+ /* Unlinked group (old_id) is still in bmain... */
+ if (grp && (&grp->id == old_id || grp->id.us == 0)) {
+ grp = BKE_group_object_find(grp, ob);
+ }
+ if (!grp) {
+ ob->flag &= ~OB_FROMGROUP;
+ }
+ }
+ if (!(ob->flag & OB_FROMGROUP)) {
+ base->flag &= ~OB_FROMGROUP;
+ }
+ }
+ }
+}
+
+static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id)
+{
+ if (ob->data == new_id) {
+ switch (GS(new_id->name)) {
+ case ID_ME:
+ multires_force_update(ob);
+ break;
+ case ID_CU:
+ BKE_curve_type_test(ob);
+ break;
+ default:
+ break;
+ }
+ test_object_modifiers(ob);
+ test_object_materials(ob, new_id);
+ }
+}
+
/**
* Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
*
@@ -263,6 +411,7 @@ static void libblock_remap_data(
printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
#endif
r_id_remap_data->id = id;
+ libblock_remap_data_preprocess(r_id_remap_data);
BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
else {
@@ -274,11 +423,16 @@ static void libblock_remap_data(
while (i--) {
ID *id_curr = lb_array[i]->first;
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
+ continue;
+ }
+
for (; id_curr; id_curr = id_curr->next) {
/* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
* the user count handling...
* XXX No more true (except for debug usage of those skipping counters). */
r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
BKE_library_foreach_ID_link(
id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
@@ -323,29 +477,6 @@ void BKE_libblock_remap_locked(
BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
BLI_assert(old_id != new_id);
- /* Some pre-process updates.
- * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
- */
- if (GS(old_id->name) == ID_OB) {
- Object *old_ob = (Object *)old_id;
- Object *new_ob = (Object *)new_id;
-
- if (new_ob == NULL) {
- Scene *sce;
- Base *base;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- base = BKE_scene_base_find(sce, old_ob);
-
- if (base) {
- id_us_min((ID *)base->object);
- BKE_scene_base_unlink(sce, base);
- MEM_freeN(base);
- }
- }
- }
- }
-
libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
if (free_notifier_reference_cb) {
@@ -385,55 +516,21 @@ void BKE_libblock_remap_locked(
*/
switch (GS(old_id->name)) {
case ID_OB:
- {
- Object *old_ob = (Object *)old_id;
- Object *new_ob = (Object *)new_id;
-
- if (old_ob->flag & OB_FROMGROUP) {
- /* Note that for Scene's BaseObject->flag, either we:
- * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
- * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
- * So in any case, no need to update them here. */
- if (BKE_group_object_find(NULL, old_ob) == NULL) {
- old_ob->flag &= ~OB_FROMGROUP;
- }
- if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
- Group *group;
- for (group = bmain->group.first; group; group = group->id.next) {
- BKE_group_object_unlink(group, NULL, NULL, NULL);
- }
- }
- else {
- new_ob->flag |= OB_FROMGROUP;
- }
- }
+ libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id);
break;
- }
case ID_GR:
- if (new_id == NULL) { /* Only affects us in case group was unlinked. */
+ if (!new_id) { /* Only affects us in case group was unlinked. */
for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
- /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
- * in one scene...). */
- for (Base *base = sce->base.first; base; base = base->next) {
- if (base->flag & OB_FROMGROUP) {
- Object *ob = base->object;
-
- if (ob->flag & OB_FROMGROUP) {
- Group *grp = BKE_group_object_find(NULL, ob);
-
- /* Unlinked group (old_id) is still in bmain... */
- if (grp && (&grp->id == old_id)) {
- grp = BKE_group_object_find(grp, ob);
- }
- if (!grp) {
- ob->flag &= ~OB_FROMGROUP;
- }
- }
- if (!(ob->flag & OB_FROMGROUP)) {
- base->flag &= ~OB_FROMGROUP;
- }
- }
- }
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+ }
+ }
+ break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
}
}
break;
@@ -460,9 +557,10 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
* \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
* (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
*/
-void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null)
+void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect)
{
- const short remap_flags = ID_REMAP_SKIP_INDIRECT_USAGE | (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
+ const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
+ (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
BKE_main_lock(bmain);
@@ -488,14 +586,14 @@ void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null)
* ... sigh
*/
void BKE_libblock_relink_ex(
- void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+ Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
{
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
- /* No need to lock here, we are only affecting given ID. */
+ /* No need to lock here, we are only affecting given ID, not bmain database. */
BLI_assert(id);
if (old_id) {
@@ -507,6 +605,50 @@ void BKE_libblock_relink_ex(
}
libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(id->name)) {
+ case ID_SCE:
+ {
+ Scene *sce = (Scene *)id;
+
+ if (old_id) {
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ {
+ libblock_remap_data_postprocess_object_fromgroup_update(
+ bmain, (Object *)old_id, (Object *)new_id);
+ break;
+ }
+ case ID_GR:
+ if (!new_id) { /* Only affects us in case group was unlinked. */
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* No choice but to check whole objects/groups. */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL);
+ }
+ for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
+ }
+ }
+ }
+ case ID_OB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
+ }
+ break;
+ default:
+ break;
+ }
}
static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
@@ -561,7 +703,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
#endif
if (do_id_user) {
- BKE_libblock_relink_ex(id, NULL, NULL, true);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
}
switch (type) {
@@ -705,7 +847,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
}
if (id->us == 0) {
- BKE_libblock_unlink(bmain, id, false);
+ BKE_libblock_unlink(bmain, id, false, false);
BKE_libblock_free(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 30dc48819e9..c4a0d0074fb 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -171,7 +171,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
}
}
if (linestyle->nodetree) {
- new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree);
+ new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree);
}
new_linestyle->r = linestyle->r;
@@ -218,8 +218,9 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
- if (linestyle->id.lib) {
- BKE_id_lib_local_paths(G.main, linestyle->id.lib, &new_linestyle->id);
+ if (ID_IS_LINKED_DATABLOCK(linestyle)) {
+ BKE_id_expand_local(&new_linestyle->id);
+ BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id);
}
return new_linestyle;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 94e53755ac4..9e070bbef22 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -533,7 +533,6 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
BezTriple *bezt = &point->bezt, *bezt_next;
- float q0[2], q1[2], q2[2], r0[2], r1[2];
bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
@@ -542,14 +541,7 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
return;
}
- interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u);
- interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u);
- interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u);
-
- interp_v2_v2v2(r0, q0, q1, u);
- interp_v2_v2v2(r1, q1, q2, u);
-
- interp_v2_v2v2(co, r0, r1, u);
+ interp_v2_v2v2v2v2_cubic(co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
}
BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
@@ -848,11 +840,11 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
return mask_new;
}
-Mask *BKE_mask_copy(Mask *mask)
+Mask *BKE_mask_copy(Main *bmain, Mask *mask)
{
Mask *mask_new;
- mask_new = BKE_libblock_copy(&mask->id);
+ mask_new = BKE_libblock_copy(bmain, &mask->id);
BLI_listbase_clear(&mask_new->masklayers);
@@ -861,8 +853,9 @@ Mask *BKE_mask_copy(Mask *mask)
/* enable fake user by default */
id_fake_user_set(&mask->id);
- if (mask->id.lib) {
- BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id);
+ if (ID_IS_LINKED_DATABLOCK(mask)) {
+ BKE_id_expand_local(&mask_new->id);
+ BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id);
}
return mask_new;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index db5ac54ada9..17811893c03 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -61,6 +61,8 @@
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -217,12 +219,12 @@ Material *BKE_material_add(Main *bmain, const char *name)
}
/* XXX keep synced with next function */
-Material *BKE_material_copy(Material *ma)
+Material *BKE_material_copy(Main *bmain, Material *ma)
{
Material *man;
int a;
- man = BKE_libblock_copy(&ma->id);
+ man = BKE_libblock_copy(bmain, &ma->id);
id_lib_extern((ID *)man->group);
@@ -237,16 +239,17 @@ Material *BKE_material_copy(Material *ma)
if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
- if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview);
-
if (ma->nodetree) {
- man->nodetree = ntreeCopyTree(ma->nodetree);
+ man->nodetree = ntreeCopyTree(bmain, ma->nodetree);
}
+ man->preview = BKE_previewimg_copy(ma->preview);
+
BLI_listbase_clear(&man->gpumaterial);
-
- if (ma->id.lib) {
- BKE_id_lib_local_paths(G.main, ma->id.lib, &man->id);
+
+ if (ID_IS_LINKED_DATABLOCK(ma)) {
+ BKE_id_expand_local(&man->id);
+ BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id);
}
return man;
@@ -282,180 +285,33 @@ Material *localize_material(Material *ma)
return man;
}
-static void extern_local_material(Material *ma)
-{
- int i;
- for (i = 0; i < MAX_MTEX; i++) {
- if (ma->mtex[i]) id_lib_extern((ID *)ma->mtex[i]->tex);
- }
-}
-
-void BKE_material_make_local(Material *ma)
+void BKE_material_make_local(Main *bmain, Material *ma)
{
- Main *bmain = G.main;
- Object *ob;
- Mesh *me;
- Curve *cu;
- MetaBall *mb;
- int a;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (ma->id.lib == NULL) return;
- /* One local user; set flag and return. */
- if (ma->id.us == 1) {
- id_clear_lib_data(bmain, &ma->id);
- extern_local_material(ma);
+ if (!ID_IS_LINKED_DATABLOCK(ma)) {
return;
}
- /* Check which other IDs reference this one to determine if it's used by
- * lib or local */
- /* test objects */
- ob = bmain->object.first;
- while (ob) {
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a] == ma) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- ob = ob->id.next;
- }
- /* test meshes */
- me = bmain->mesh.first;
- while (me) {
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- me = me->id.next;
- }
- /* test curves */
- cu = bmain->curve.first;
- while (cu) {
- if (cu->mat) {
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a] == ma) {
- if (cu->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- cu = cu->id.next;
- }
- /* test mballs */
- mb = bmain->mball.first;
- while (mb) {
- if (mb->mat) {
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a] == ma) {
- if (mb->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- mb = mb->id.next;
- }
-
- /* Only local users. */
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &ma->id);
- extern_local_material(ma);
- }
- /* Both user and local, so copy. */
- else if (is_local && is_lib) {
- Material *ma_new = BKE_material_copy(ma);
+ BKE_library_ID_test_usages(bmain, ma, &is_local, &is_lib);
- ma_new->id.us = 0;
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &ma->id);
+ BKE_id_expand_local(&ma->id);
+ }
+ else {
+ Material *ma_new = BKE_material_copy(bmain, ma);
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ma->id.lib, &ma_new->id);
+ ma_new->id.us = 0;
- /* do objects */
- ob = bmain->object.first;
- while (ob) {
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a] == ma) {
- if (ob->id.lib == NULL) {
- ob->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- ob = ob->id.next;
+ BKE_libblock_remap(bmain, ma, ma_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
- /* do meshes */
- me = bmain->mesh.first;
- while (me) {
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- if (me->id.lib == NULL) {
- me->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- me = me->id.next;
- }
- /* do curves */
- cu = bmain->curve.first;
- while (cu) {
- if (cu->mat) {
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a] == ma) {
- if (cu->id.lib == NULL) {
- cu->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- cu = cu->id.next;
- }
- /* do mballs */
- mb = bmain->mball.first;
- while (mb) {
- if (mb->mat) {
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a] == ma) {
- if (mb->id.lib == NULL) {
- mb->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- mb = mb->id.next;
- }
- }
-}
-
-/* for curve, mball, mesh types */
-void extern_local_matarar(struct Material **matar, short totcol)
-{
- short i;
- for (i = 0; i < totcol; i++) {
- id_lib_extern((ID *)matar[i]);
}
}
@@ -611,7 +467,7 @@ void BKE_material_append_id(ID *id, Material *ma)
(*matar)[(*totcol)++] = ma;
id_us_plus((ID *)ma);
- test_object_materials(G.main, id);
+ test_all_objects_materials(G.main, id);
}
}
@@ -637,7 +493,7 @@ Material *BKE_material_pop_id(ID *id, int index_i, bool update_data)
(*totcol)--;
*matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol));
- test_object_materials(G.main, id);
+ test_all_objects_materials(G.main, id);
}
if (update_data) {
@@ -776,7 +632,19 @@ void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
}
-void test_object_materials(Main *bmain, ID *id)
+void test_object_materials(Object *ob, ID *id)
+{
+ /* make the ob mat-array same size as 'ob->data' mat-array */
+ const short *totcol;
+
+ if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
+ return;
+ }
+
+ BKE_material_resize_object(ob, *totcol, false);
+}
+
+void test_all_objects_materials(Main *bmain, ID *id)
{
/* make the ob mat-array same size as 'ob->data' mat-array */
Object *ob;
@@ -839,7 +707,7 @@ void assign_material_id(ID *id, Material *ma, short act)
if (ma)
id_us_plus(&ma->id);
- test_object_materials(G.main, id);
+ test_all_objects_materials(G.main, id);
}
void assign_material(Object *ob, Material *ma, short act, int assign_type)
@@ -852,8 +720,8 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
if (act < 1) act = 1;
/* prevent crashing when using accidentally */
- BLI_assert(ob->id.lib == NULL);
- if (ob->id.lib) return;
+ BLI_assert(!ID_IS_LINKED_DATABLOCK(ob));
+ if (ID_IS_LINKED_DATABLOCK(ob)) return;
/* test arraylens */
@@ -924,7 +792,7 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
if (ma)
id_us_plus(&ma->id);
- test_object_materials(G.main, ob->data);
+ test_object_materials(ob, ob->data);
}
@@ -1121,7 +989,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
Group *group;
for (group = G.main->group.first; group; group = group->id.next) {
- if (!group->id.lib && STREQ(group->id.name, ma->group->id.name)) {
+ if (!ID_IS_LINKED_DATABLOCK(group) && STREQ(group->id.name, ma->group->id.name)) {
ma->group = group;
}
}
@@ -2158,7 +2026,7 @@ static void convert_tfacematerial(Main *main, Material *ma)
}
/* create a new material */
else {
- mat_new = BKE_material_copy(ma);
+ mat_new = BKE_material_copy(main, ma);
if (mat_new) {
/* rename the material*/
BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
@@ -2230,7 +2098,7 @@ int do_version_tface(Main *main)
/* 1st part: marking mesh materials to update */
for (me = main->mesh.first; me; me = me->id.next) {
- if (me->id.lib) continue;
+ if (ID_IS_LINKED_DATABLOCK(me)) continue;
/* get the active tface layer */
index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
@@ -2284,7 +2152,7 @@ int do_version_tface(Main *main)
* at doversion time: direct_link might not have happened on it,
* so ma->mtex is not pointing to valid memory yet.
* later we could, but it's better not */
- else if (ma->id.lib)
+ else if (ID_IS_LINKED_DATABLOCK(ma))
continue;
/* material already marked as disputed */
@@ -2349,7 +2217,7 @@ int do_version_tface(Main *main)
/* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
- if (ma->id.lib) continue;
+ if (ID_IS_LINKED_DATABLOCK(ma)) continue;
/* disputed material */
if (ma->game.flag == MAT_BGE_DISPUTED) {
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 685cd35fc20..9a0a6e3540c 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -59,6 +59,8 @@
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_displist.h"
#include "BKE_mball.h"
#include "BKE_object.h"
@@ -100,12 +102,12 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-MetaBall *BKE_mball_copy(MetaBall *mb)
+MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
{
MetaBall *mbn;
int a;
- mbn = BKE_libblock_copy(&mb->id);
+ mbn = BKE_libblock_copy(bmain, &mb->id);
BLI_duplicatelist(&mbn->elems, &mb->elems);
@@ -117,65 +119,40 @@ MetaBall *BKE_mball_copy(MetaBall *mb)
mbn->editelems = NULL;
mbn->lastelem = NULL;
- if (mb->id.lib) {
- BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id);
+ if (ID_IS_LINKED_DATABLOCK(mb)) {
+ BKE_id_expand_local(&mbn->id);
+ BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id);
}
return mbn;
}
-static void extern_local_mball(MetaBall *mb)
+void BKE_mball_make_local(Main *bmain, MetaBall *mb)
{
- if (mb->mat) {
- extern_local_matarar(mb->mat, mb->totcol);
- }
-}
-
-void BKE_mball_make_local(MetaBall *mb)
-{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (mb->id.lib == NULL) return;
- if (mb->id.us == 1) {
- id_clear_lib_data(bmain, &mb->id);
- extern_local_mball(mb);
-
+
+ if (!ID_IS_LINKED_DATABLOCK(mb)) {
return;
}
- for (ob = G.main->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == mb) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
+ BKE_library_ID_test_usages(bmain, mb, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &mb->id);
+ BKE_id_expand_local(&mb->id);
}
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &mb->id);
- extern_local_mball(mb);
- }
- else if (is_local && is_lib) {
- MetaBall *mb_new = BKE_mball_copy(mb);
- mb_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, mb->id.lib, &mb_new->id);
-
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- if (ob->data == mb) {
- if (ob->id.lib == NULL) {
- ob->data = mb_new;
- id_us_plus(&mb_new->id);
- id_us_min(&mb->id);
- }
- }
+ else {
+ MetaBall *mb_new = BKE_mball_copy(bmain, mb);
+
+ mb_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, mb, mb_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index e8418e876bb..2068854421f 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1159,7 +1159,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
/* too big stiffness seems only ugly due to linear interpolation
- * no need to have possibility for too big stiffness */
+ * no need to have possibility for too big stiffness */
if (ml->s > 10.0f) new_ml->s = 10.0f;
else new_ml->s = ml->s;
@@ -1294,7 +1294,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob,
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
/* don't polygonize metaballs with too high resolution (base mball to small)
- * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
+ * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2]))
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index f82e5cf61b3..787b9905734 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -49,6 +49,8 @@
#include "BKE_mesh.h"
#include "BKE_displist.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
@@ -491,15 +493,13 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
return me;
}
-Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me)
+Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
{
Mesh *men;
- MTFace *tface;
- MTexPoly *txface;
- int a, i;
+ int a;
const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */
- men = BKE_libblock_copy_ex(bmain, &me->id);
+ men = BKE_libblock_copy(bmain, &me->id);
men->mat = MEM_dupallocN(me->mat);
for (a = 0; a < men->totcol; a++) {
@@ -520,53 +520,32 @@ Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me)
BKE_mesh_update_customdata_pointers(men, do_tessface);
- /* ensure indirect linked data becomes lib-extern */
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++)
- if (tface->tpage)
- id_lib_extern((ID *)tface->tpage);
- }
- }
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- txface = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, txface++)
- if (txface->tpage)
- id_lib_extern((ID *)txface->tpage);
- }
- }
-
men->edit_btmesh = NULL;
men->mselect = MEM_dupallocN(men->mselect);
men->bb = MEM_dupallocN(men->bb);
-
- men->key = BKE_key_copy(me->key);
- if (men->key) men->key->from = (ID *)men;
- if (me->id.lib) {
+ if (me->key) {
+ men->key = BKE_key_copy(bmain, me->key);
+ men->key->from = (ID *)men;
+ }
+
+ if (ID_IS_LINKED_DATABLOCK(me)) {
+ BKE_id_expand_local(&men->id);
BKE_id_lib_local_paths(bmain, me->id.lib, &men->id);
}
return men;
}
-Mesh *BKE_mesh_copy(Mesh *me)
-{
- return BKE_mesh_copy_ex(G.main, me);
-}
-
-BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
+BMesh *BKE_mesh_to_bmesh(
+ Mesh *me, Object *ob,
+ const bool add_key_index, const struct BMeshCreateParams *params)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(&allocsize, params);
BM_mesh_bm_from_me(
bm, me, (&(struct BMeshFromMeshParams){
@@ -576,49 +555,8 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
return bm;
}
-static void expand_local_mesh(Mesh *me)
-{
- id_lib_extern((ID *)me->texcomesh);
-
- if (me->mtface || me->mtpoly) {
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, txface++) {
- /* special case: ima always local immediately */
- if (txface->tpage) {
- id_lib_extern((ID *)txface->tpage);
- }
- }
- }
- }
-
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- MTFace *tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++) {
- /* special case: ima always local immediately */
- if (tface->tpage) {
- id_lib_extern((ID *)tface->tpage);
- }
- }
- }
- }
- }
-
- if (me->mat) {
- extern_local_matarar(me->mat, me->totcol);
- }
-}
-
-void BKE_mesh_make_local(Mesh *me)
+void BKE_mesh_make_local(Main *bmain, Mesh *me)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
@@ -626,38 +564,26 @@ void BKE_mesh_make_local(Mesh *me)
* - mixed: make copy
*/
- if (me->id.lib == NULL) return;
- if (me->id.us == 1) {
- id_clear_lib_data(bmain, &me->id);
- expand_local_mesh(me);
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
return;
}
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (me == ob->data) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &me->id);
- expand_local_mesh(me);
- }
- else if (is_local && is_lib) {
- Mesh *me_new = BKE_mesh_copy(me);
- me_new->id.us = 0;
+ BKE_library_ID_test_usages(bmain, me, &is_local, &is_lib);
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &me->id);
+ if (me->key) {
+ BKE_key_make_local(bmain, me->key);
+ }
+ BKE_id_expand_local(&me->id);
+ }
+ else {
+ Mesh *me_new = BKE_mesh_copy(bmain, me);
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, me->id.lib, &me_new->id);
+ me_new->id.us = 0;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (me == ob->data) {
- if (ob->id.lib == NULL) {
- BKE_mesh_assign_object(ob, me_new);
- }
- }
+ BKE_libblock_remap(bmain, me, me_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
@@ -1008,7 +934,7 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me)
id_us_plus((ID *)me);
}
- test_object_materials(G.main, (ID *)me);
+ test_object_materials(ob, (ID *)me);
test_object_modifiers(ob);
}
@@ -2338,7 +2264,7 @@ Mesh *BKE_mesh_new_from_object(
BKE_object_free_modifiers(tmpobj);
/* copies the data */
- copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data);
+ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
/* temporarily set edit so we get updates from edit mode, but
* also because for text datablocks copying it while in edit
@@ -2419,7 +2345,7 @@ Mesh *BKE_mesh_new_from_object(
/* copies object and modifiers (but not the data) */
if (cage) {
/* copies the data */
- tmpmesh = BKE_mesh_copy_ex(bmain, ob->data);
+ tmpmesh = BKE_mesh_copy(bmain, ob->data);
/* if not getting the original caged mesh, get final derived mesh */
}
else {
@@ -2516,8 +2442,8 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_tessface_ensure(tmpmesh);
}
- /* make sure materials get updated in objects */
- test_object_materials(bmain, &tmpmesh->id);
+ /* make sure materials get updated in object */
+ test_object_materials(tmpobj ? tmpobj : ob, &tmpmesh->id);
return tmpmesh;
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 59eeb5dd96a..936b014cca3 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -700,7 +700,7 @@ void test_object_modifiers(Object *ob)
*/
const char *modifier_path_relbase(Object *ob)
{
- if (G.relbase_valid || ob->id.lib) {
+ if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) {
return ID_BLEND_PATH(G.main, &ob->id);
}
else {
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 18f3db6bd15..0838630a6cb 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -211,7 +211,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do
bm = em->bm;
}
else {
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
}
DM_to_bmesh_ex(dm, bm, do_tessellate);
@@ -233,7 +235,9 @@ BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal)
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
DM_to_bmesh_ex(dm, bm, calc_face_normal);
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 0527df67033..c321bc92a71 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -183,7 +183,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
}
else {
/* use a copy of the action instead (user count shouldn't have changed yet) */
- strip_d->act = BKE_action_copy(strip_d->act);
+ strip_d->act = BKE_action_copy(G.main, strip_d->act);
}
}
@@ -1291,7 +1291,7 @@ void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
if (IS_EQF(mapping, 0.0f) == 0)
strip->end = (actlen * mapping) + strip->start;
- /* make sure we don't overlap our neighbours */
+ /* make sure we don't overlap our neighbors */
nlastrip_fix_resize_overlaps(strip);
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index d78ddc41e97..296a00388c4 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -58,6 +58,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -1205,7 +1207,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* is ntree part of library? */
if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
- newtree = BKE_libblock_copy(&ntree->id);
+ newtree = BKE_libblock_copy(bmain, &ntree->id);
}
else {
newtree = BKE_libblock_copy_nolib(&ntree->id, true);
@@ -1289,7 +1291,8 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* node tree will generate its own interface type */
newtree->interface_type = NULL;
- if (ntree->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ntree)) {
+ BKE_id_expand_local(&newtree->id);
BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id);
}
@@ -1300,9 +1303,9 @@ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user
{
return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
-bNodeTree *ntreeCopyTree(bNodeTree *ntree)
+bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree)
{
- return ntreeCopyTree_ex(ntree, G.main, true);
+ return ntreeCopyTree_ex(ntree, bmain, true);
}
/* use when duplicating scenes */
@@ -1948,70 +1951,33 @@ bNodeTree *ntreeFromID(ID *id)
}
}
-static void extern_local_ntree(bNodeTree *ntree)
+void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- id_lib_extern(node->id);
- }
- }
-}
-
-void ntreeMakeLocal(bNodeTree *ntree, bool id_in_mainlist)
-{
- Main *bmain = G.main;
- bool lib = false, local = false;
+ bool is_lib = false, is_local = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (ntree->id.lib == NULL) return;
- if (ntree->id.us == 1) {
- id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
- extern_local_ntree(ntree);
+
+ if (!ID_IS_LINKED_DATABLOCK(ntree)) {
return;
}
-
- /* now check users of groups... again typedepending, callback... */
- FOREACH_NODETREE(G.main, tntree, owner_id) {
- bNode *node;
- /* find if group is in tree */
- for (node = tntree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)ntree) {
- if (owner_id->lib)
- lib = true;
- else
- local = true;
- }
+
+ BKE_library_ID_test_usages(bmain, ntree, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
+ BKE_id_expand_local(&ntree->id);
+ }
+ else {
+ bNodeTree *ntree_new = ntreeCopyTree(bmain, ntree);
+
+ ntree_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, ntree, ntree_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
- } FOREACH_NODETREE_END
-
- /* if all users are local, we simply make tree local */
- if (local && !lib) {
- id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
- extern_local_ntree(ntree);
- }
- else if (local && lib) {
- /* this is the mixed case, we copy the tree and assign it to local users */
- bNodeTree *newtree = ntreeCopyTree(ntree);
-
- newtree->id.us = 0;
-
- FOREACH_NODETREE(G.main, tntree, owner_id) {
- bNode *node;
- /* find if group is in tree */
- for (node = tntree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)ntree) {
- if (owner_id->lib == NULL) {
- node->id = (ID *)newtree;
- id_us_plus(&newtree->id);
- id_us_min(&ntree->id);
- }
- }
- }
- } FOREACH_NODETREE_END
}
}
@@ -2715,7 +2681,7 @@ void BKE_node_clipboard_add_node(bNode *node)
node_info->id = node->id;
if (node->id) {
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
- if (node->id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(node->id)) {
BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
}
else {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 357f01e0961..00c25bed1f7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -95,6 +95,8 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
@@ -931,7 +933,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
ModifierData *md;
int a;
- obn = BKE_libblock_copy_ex(bmain, &ob->id);
+ obn = BKE_libblock_copy(bmain, &ob->id);
if (ob->totcol) {
obn->mat = MEM_dupallocN(ob->mat);
@@ -1001,11 +1003,11 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
copy_object_lod(obn, ob);
-
/* Copy runtime surve data. */
obn->curve_cache = NULL;
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
+ BKE_id_expand_local(&obn->id);
BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
}
@@ -1016,41 +1018,13 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
}
/* copy objects, will re-initialize cached simulation data */
-Object *BKE_object_copy(Object *ob)
+Object *BKE_object_copy(Main *bmain, Object *ob)
{
- return BKE_object_copy_ex(G.main, ob, false);
+ return BKE_object_copy_ex(bmain, ob, false);
}
-static void extern_local_object__modifiersForeachIDLink(
- void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+void BKE_object_make_local(Main *bmain, Object *ob)
{
- if (*idpoin) {
- /* intentionally omit ID_OB */
- if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) {
- id_lib_extern(*idpoin);
- }
- }
-}
-
-static void extern_local_object(Object *ob)
-{
- id_lib_extern((ID *)ob->data);
- id_lib_extern((ID *)ob->dup_group);
- id_lib_extern((ID *)ob->poselib);
- id_lib_extern((ID *)ob->gpd);
-
- extern_local_matarar(ob->mat, ob->totcol);
-
- modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL);
-
- ob->preview = NULL;
-}
-
-void BKE_object_make_local(Object *ob)
-{
- Main *bmain = G.main;
- Scene *sce;
- Base *base;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
@@ -1058,74 +1032,40 @@ void BKE_object_make_local(Object *ob)
* - mixed: make copy
*/
- if (ob->id.lib == NULL) return;
-
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
-
- if (ob->id.us == 1) {
- id_clear_lib_data(bmain, &ob->id);
- extern_local_object(ob);
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ return;
}
- else {
- for (sce = bmain->scene.first; sce && ELEM(0, is_lib, is_local); sce = sce->id.next) {
- if (BKE_scene_base_find(sce, ob)) {
- if (sce->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- if (is_local && is_lib == false) {
+ BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
- extern_local_object(ob);
+ BKE_id_expand_local(&ob->id);
}
- else if (is_local && is_lib) {
- Object *ob_new = BKE_object_copy(ob);
+ else {
+ Object *ob_new = BKE_object_copy(bmain, ob);
ob_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ob->id.lib, &ob_new->id);
-
- sce = bmain->scene.first;
- while (sce) {
- if (sce->id.lib == NULL) {
- base = sce->base.first;
- while (base) {
- if (base->object == ob) {
- base->object = ob_new;
- id_us_plus(&ob_new->id);
- id_us_min(&ob->id);
- }
- base = base->next;
- }
- }
- sce = sce->id.next;
- }
+ ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+
+ BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
-/*
- * Returns true if the Object is a from an external blend file (libdata)
- */
+/* Returns true if the Object is from an external blend file (libdata) */
bool BKE_object_is_libdata(Object *ob)
{
- if (!ob) return false;
- if (ob->proxy) return false;
- if (ob->id.lib) return true;
- return false;
+ return (ob && ID_IS_LINKED_DATABLOCK(ob));
}
-/* Returns true if the Object data is a from an external blend file (libdata) */
+/* Returns true if the Object data is from an external blend file (libdata) */
bool BKE_object_obdata_is_libdata(Object *ob)
{
- if (!ob) return false;
- if (ob->proxy && (ob->data == NULL || ((ID *)ob->data)->lib == NULL)) return false;
- if (ob->id.lib) return true;
- if (ob->data == NULL) return false;
- if (((ID *)ob->data)->lib) return true;
-
- return false;
+ /* Linked objects with local obdata are forbidden! */
+ BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true));
+ return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data));
}
/* *************** PROXY **************** */
@@ -1172,7 +1112,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* only on local objects because this causes indirect links
* 'a -> b -> c', blend to point directly to a.blend
* when a.blend has a proxy thats linked into c.blend */
- if (ob->id.lib == NULL)
+ if (!ID_IS_LINKED_DATABLOCK(ob))
id_lib_extern((ID *)dtar->id);
}
}
@@ -1190,7 +1130,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
{
/* paranoia checks */
- if (ob->id.lib || target->id.lib == NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) {
printf("cannot make proxy\n");
return;
}
@@ -2567,7 +2507,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
printf("recalcob %s\n", ob->id.name + 2);
/* handle proxy copy for target */
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
Object *obg = ob->proxy_from->proxy_group;
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 8df501bd106..b5cb59da7d2 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
break;
}
case OB_ARMATURE:
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
@@ -268,7 +268,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
// XXX: it's almost redundant now...
/* Handle proxy copy for target, */
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
if (ob->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = ob->proxy_from->proxy_group;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 1c318dfd115..489fc2f3710 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
+ if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) {
if (ima->source == IMA_SRC_FILE) {
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
@@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
}
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
- if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == false) {
+ if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) {
vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
tot ++;
}
}
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
- if (sound->packedfile == NULL && sound->id.lib == NULL) {
+ if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) {
sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
tot++;
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 58ec75dc706..ff69f381b06 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -276,16 +276,14 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
/* reserve size is rough guess */
GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
- int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface,
+ int (*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface,
"bvh node face vert indices");
- node->face_vert_indices = (const int (*)[4])face_vert_indices;
+ node->face_vert_indices = (const int (*)[3])face_vert_indices;
for (int i = 0; i < totface; ++i) {
const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
- const int sides = 3;
-
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < 3; ++j) {
face_vert_indices[i][j] =
map_insert_vert(bvh, map, &node->face_verts,
&node->uniq_verts, bvh->mloop[lt->tri[j]].v);
@@ -690,8 +688,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting)
{
if (UNLIKELY(iter->stacksize == iter->stackspace)) {
iter->stackspace *= 2;
-
- if (iter->stackspace != STACK_FIXED_DEPTH) {
+ if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) {
iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
}
else {
@@ -1496,12 +1493,18 @@ typedef struct {
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
{
RaycastData *rcd = data_v;
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
- if (rcd->original)
- BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
- else
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
+ if (rcd->original) {
+ /* BKE_pbvh_node_get_original_BB */
+ bb_min = node->orig_vb.bmin;
+ bb_max = node->orig_vb.bmax;
+ }
+ else {
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
+ }
return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
@@ -1801,17 +1804,21 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
{
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
{
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 88dc63d6cb2..55f9f384081 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -69,11 +69,134 @@
static void pbvh_bmesh_verify(PBVH *bvh);
#endif
+/** \name BMesh Utility API
+ *
+ * Use some local functions which assume triangles.
+ * \{ */
+
+/**
+ * Typically using BM_LOOPS_OF_VERT and BM_FACES_OF_VERT iterators are fine,
+ * however this is an area where performance matters so do it in-line.
+ *
+ * Take care since 'break' won't works as expected within these macros!
+ */
+
+#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \
+{ \
+ struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \
+ _iter.v = v_; \
+ if (_iter.v->e) { \
+ _iter.e_iter = _iter.e_first = _iter.v->e; \
+ do { \
+ if (_iter.e_iter->l) { \
+ _iter.l_iter_radial = _iter.e_iter->l; \
+ do { \
+ if (_iter.l_iter_radial->v == _iter.v) { \
+ l_iter_radial_ = _iter.l_iter_radial;
+
+#define BM_LOOPS_OF_VERT_ITER_END \
+ } \
+ } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \
+ } \
+ } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \
+ } \
+} ((void)0)
+
+#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \
+{ \
+ BMLoop *l_iter_radial_; \
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \
+ f_iter_ = l_iter_radial_->f; \
+
+#define BM_FACES_OF_VERT_ITER_END \
+ } \
+ BM_LOOPS_OF_VERT_ITER_END; \
+}
+
+static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
+{
+ e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
+}
+
+BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
+{
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+
+ BLI_assert(f->len == 3);
+
+ r_index[0] = BM_elem_index_get(l->v); l = l->next;
+ r_index[1] = BM_elem_index_get(l->v); l = l->next;
+ r_index[2] = BM_elem_index_get(l->v);
+}
+
+/**
+ * A version of #BM_face_exists, optimized for triangles
+ * when we know the loop and the opposite vertex.
+ *
+ * Check if any triangle is formed by (l_radial_first->v, l_radial_first->next->v, v_opposite),
+ * at either winding (since its a triangle no special checks are needed).
+ *
+ * <pre>
+ * l_radial_first->v & l_radial_first->next->v
+ * +---+
+ * | /
+ * | /
+ * + v_opposite
+ * </pre>
+ *
+ * Its assumed that \a l_radial_first is never forming the target face.
+ */
+static bool bm_face_exists_tri_from_loop_vert(
+ BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+{
+ BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
+ if (l_radial_first->radial_next != l_radial_first) {
+ BMLoop *l_radial_iter = l_radial_first->radial_next;
+ do {
+ BLI_assert(l_radial_iter->f->len == 3);
+ if (l_radial_iter->prev->v == v_opposite) {
+ *r_face_existing = l_radial_iter->f;
+ return true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ return false;
+}
+
+/**
+ * Uses a map of vertices to lookup the final target.
+ * References can't point to previous items (would cause infinite loop).
+ */
+static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
+{
+ while (true) {
+ BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
+ if (v_next_p == NULL) {
+ /* not remapped*/
+ return v;
+ }
+ else if (*v_next_p == NULL) {
+ /* removed and not remapped */
+ return NULL;
+ }
+ else {
+ /* remapped */
+ v = *v_next_p;
+ }
+ }
+}
+
+/** \} */
+
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_node_finalize(
+ PBVH *bvh, const int node_index,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
GSetIterator gs_iter;
PBVHNode *n = &bvh->nodes[node_index];
@@ -200,7 +323,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
break;
}
}
-
+
/* Clear this node */
/* Mark this node's unique verts as unclaimed */
@@ -224,18 +347,18 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
if (n->layer_disp)
MEM_freeN(n->layer_disp);
-
+
n->bm_faces = NULL;
n->bm_unique_verts = NULL;
n->bm_other_verts = NULL;
n->layer_disp = NULL;
-
+
if (n->draw_buffers) {
GPU_free_pbvh_buffers(n->draw_buffers);
n->draw_buffers = NULL;
}
n->flag &= ~PBVH_Leaf;
-
+
/* Recurse */
pbvh_bmesh_node_split(bvh, bbc_array, children);
pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
@@ -292,6 +415,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
+#if 0
static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
{
switch (ele->head.htype) {
@@ -304,7 +428,7 @@ static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
}
-static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
+static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
{
const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
@@ -316,18 +440,45 @@ static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
return node_index;
}
-static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
+static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
}
/* typecheck */
-#define pbvh_bmesh_node_lookup_index(bvh, key) ( \
+#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup_index(bvh, key))
-#define pbvh_bmesh_node_lookup(bvh, key) ( \
+ pbvh_bmesh_node_index_from_elem(bvh, key))
+#define pbvh_bmesh_node_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup(bvh, key))
+ pbvh_bmesh_node_from_elem(bvh, key))
+#endif
+
+BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+}
static BMVert *pbvh_bmesh_vert_create(
@@ -357,6 +508,9 @@ static BMVert *pbvh_bmesh_vert_create(
return v;
}
+/**
+ * \note Callers are responsible for checking if the face exists before adding.
+ */
static BMFace *pbvh_bmesh_face_create(
PBVH *bvh, int node_index,
BMVert *v_tri[3], BMEdge *e_tri[3],
@@ -367,7 +521,7 @@ static BMFace *pbvh_bmesh_face_create(
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
+ BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -387,16 +541,16 @@ static BMFace *pbvh_bmesh_face_create(
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
- BMIter bm_iter;
BMFace *f;
int count = 0;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -407,19 +561,19 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
{
- BMIter bm_iter;
- BMFace *f;
int count = 0;
+ BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
- break;
+ return count;
}
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -427,16 +581,17 @@ static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *
/* Return a node that uses vertex 'v' other than its current owner */
static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
- BMIter bm_iter;
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
BMFace *f;
- PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v);
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node != current_node)
+ if (f_node != current_node) {
return f_node;
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
return NULL;
}
@@ -445,7 +600,7 @@ static void pbvh_bmesh_vert_ownership_transfer(
PBVH *bvh, PBVHNode *new_owner,
BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -469,36 +624,36 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
- BMIter bm_iter;
BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
- if (f_node_index_prev == f_node_index)
- continue;
- f_node_index_prev = f_node_index;
+ if (f_node_index_prev != f_node_index) {
+ f_node_index_prev = f_node_index;
- PBVHNode *f_node = &bvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ PBVHNode *f_node = &bvh->nodes[f_node_index];
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- /* Remove current ownership */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ /* Remove current ownership */
+ BLI_gset_remove(f_node->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
- BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
}
static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
@@ -923,13 +1078,6 @@ static void short_edge_queue_create(
/*************************** Topology update **************************/
-static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
-{
- e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
-}
-
static void pbvh_bmesh_split_edge(
EdgeQueueContext *eq_ctx, PBVH *bvh,
BMEdge *e, BLI_Buffer *edge_loops)
@@ -1101,15 +1249,16 @@ static bool pbvh_bmesh_subdivide_long_edges(
static void pbvh_bmesh_collapse_edge(
PBVH *bvh, BMEdge *e,
BMVert *v1, BMVert *v2,
- GSet *deleted_verts,
+ GHash *deleted_verts,
BLI_Buffer *deleted_faces,
EdgeQueueContext *eq_ctx)
{
BMVert *v_del, *v_conn;
- float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset);
/* one of the two vertices may be masked, select the correct one for deletion */
- if (mask_v1 < 1.0f) {
+ if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
+ BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset))
+ {
v_del = v1;
v_conn = v2;
}
@@ -1141,33 +1290,43 @@ static void pbvh_bmesh_collapse_edge(
* really buy anything. */
BLI_buffer_empty(deleted_faces);
- BMIter bm_iter;
- BMFace *f;
+ BMLoop *l;
- BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) {
- BMVert *v_tri[3];
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) {
BMFace *existing_face;
/* Get vertices, replace use of v_del with v_conn */
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
+ BMFace *f = l->f;
+#if 0
+ BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
for (int i = 0; i < 3; i++) {
if (v_tri[i] == v_del) {
v_tri[i] = v_conn;
}
}
+#endif
/* Check if a face using these vertices already exists. If so,
* skip adding this face and mark the existing one for
* deletion as well. Prevents extraneous "flaps" from being
* created. */
- if (BM_face_exists(v_tri, 3, &existing_face)) {
+#if 0
+ if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+#else
+ if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+#endif
+ {
BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
+ BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
+
+ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
@@ -1180,6 +1339,7 @@ static void pbvh_bmesh_collapse_edge(
BLI_buffer_append(deleted_faces, BMFace *, f);
}
+ BM_LOOPS_OF_VERT_ITER_END;
/* Delete the tagged faces */
for (int i = 0; i < deleted_faces->count; i++) {
@@ -1209,10 +1369,14 @@ static void pbvh_bmesh_collapse_edge(
* remove them from the PBVH */
for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- BLI_gset_insert(deleted_verts, v_tri[j]);
pbvh_bmesh_vert_remove(bvh, v_tri[j]);
BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+
+ if (v_tri[j] == v_conn) {
+ v_conn = NULL;
+ }
+ BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
BM_vert_kill(bvh->bm, v_tri[j]);
}
}
@@ -1220,17 +1384,26 @@ static void pbvh_bmesh_collapse_edge(
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
- if (!BLI_gset_haskey(deleted_verts, v_conn)) {
+ if (v_conn != NULL) {
BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
+
+ /* update boundboxes attached to the connected vertex
+ * note that we can often get-away without this but causes T48779 */
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
}
/* Delete v_del */
BLI_assert(!BM_vert_face_check(v_del));
- BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ /* v_conn == NULL is OK */
+ BLI_ghash_insert(deleted_verts, v_del, v_conn);
BM_vert_kill(bvh->bm, v_del);
}
@@ -1241,17 +1414,19 @@ static bool pbvh_bmesh_collapse_short_edges(
{
const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
bool any_collapsed = false;
- GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts");
+ /* deleted verts point to vertices they were merged into, or NULL when removed. */
+ GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
- BMVert *v1 = pair[0], *v2 = pair[1];
+ BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
/* Check the verts still exist */
- if (BLI_gset_haskey(deleted_verts, v1) ||
- BLI_gset_haskey(deleted_verts, v2))
+ if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
+ !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) ||
+ (v1 == v2))
{
continue;
}
@@ -1285,7 +1460,7 @@ static bool pbvh_bmesh_collapse_short_edges(
deleted_faces, eq_ctx);
}
- BLI_gset_free(deleted_verts, NULL);
+ BLI_ghash_free(deleted_verts, NULL, NULL);
return any_collapsed;
}
@@ -1406,18 +1581,23 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-typedef struct FastNodeBuildInfo {
+struct FastNodeBuildInfo {
int totface; /* number of faces */
int start; /* start of faces in array */
struct FastNodeBuildInfo *child1;
struct FastNodeBuildInfo *child2;
-} FastNodeBuildInfo;
+};
-/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
- * to a sub part of the arrays */
-static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
+/**
+ * Recursively split the node if it exceeds the leaf_limit.
+ * This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays
+ */
+static void pbvh_bmesh_node_limit_ensure_fast(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node,
+ MemArena *arena)
{
- FastNodeBuildInfo *child1, *child2;
+ struct FastNodeBuildInfo *child1, *child2;
if (node->totface <= bvh->leaf_limit) {
return;
@@ -1497,8 +1677,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
* each sequential part belonging to one node only */
BLI_assert((num_child1 + num_child2) == node->totface);
- node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
- node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
child1->totface = num_child1;
child1->start = node->start;
@@ -1510,7 +1690,9 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
}
-static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+static void pbvh_bmesh_create_nodes_fast_recursive(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array,
+ struct FastNodeBuildInfo *node, int node_index)
{
PBVHNode *n = bvh->nodes + node_index;
/* two cases, node does not have children or does have children */
@@ -1651,7 +1833,7 @@ void BKE_pbvh_build_bmesh(
bm->elem_index_dirty |= BM_FACE;
/* setup root node */
- FastNodeBuildInfo rootnode = {0};
+ struct FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
@@ -1693,12 +1875,14 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
- &deleted_faces);
+ modified |= pbvh_bmesh_collapse_short_edges(
+ &eq_ctx, bvh, &deleted_faces);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -1706,15 +1890,18 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Subdivide) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ modified |= pbvh_bmesh_subdivide_long_edges(
+ &eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
-
+
/* Unmark nodes */
for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -1735,16 +1922,6 @@ bool BKE_pbvh_bmesh_update_topology(
return modified;
}
-BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
-{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
-
- BLI_assert(f->len == 3);
-
- r_index[0] = BM_elem_index_get(l->v); l = l->next;
- r_index[1] = BM_elem_index_get(l->v); l = l->next;
- r_index[2] = BM_elem_index_get(l->v);
-}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
@@ -1858,8 +2035,8 @@ static void pbvh_bmesh_print(PBVH *bvh)
BMFace *f;
BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, f));
+ BM_elem_index_get(f),
+ pbvh_bmesh_node_index_from_face(bvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
@@ -1867,7 +2044,7 @@ static void pbvh_bmesh_print(PBVH *bvh)
BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, v));
+ pbvh_bmesh_node_index_from_vert(bvh, v));
}
for (int n = 0; n < bvh->totnode; n++) {
@@ -1909,17 +2086,23 @@ static void pbvh_bmesh_verify(PBVH *bvh)
{
/* build list of faces & verts to lookup */
GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
- BMFace *f;
BMIter iter;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(faces_all, f);
+
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BLI_gset_insert(faces_all, f);
+ }
}
GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_insert(verts_all, v);
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_insert(verts_all, v);
+ }
}
}
@@ -1936,76 +2119,83 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BLI_assert(totvert == BLI_gset_size(verts_all));
}
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BMIter bm_iter;
- BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BMIter bm_iter;
+ BMVert *v;
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
- /* Check that the face's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the face's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the face's node knows it owns the face */
- BLI_assert(BLI_gset_haskey(n->bm_faces, f));
+ /* Check that the face's node knows it owns the face */
+ BLI_assert(BLI_gset_haskey(n->bm_faces, f));
- /* Check the face's vertices... */
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- PBVHNode *nv;
+ /* Check the face's vertices... */
+ BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+ PBVHNode *nv;
- /* Check that the vertex is in the node */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
- BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex is in the node */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
+ BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
+ /* Check that the vertex has a node owner */
+ nv = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vertex's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
+ /* Check that the vertex's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ }
}
}
/* Check verts */
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- /* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
- continue;
- }
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ /* vertex isn't tracked */
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ continue;
+ }
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vert's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the vert's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the vert's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
+ /* Check that the vert's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vert's node also contains one of the vert's
- * adjacent faces */
- bool found = false;
- BMIter bm_iter;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
- found = true;
- break;
+ /* Check that the vert's node also contains one of the vert's
+ * adjacent faces */
+ bool found = false;
+ BMIter bm_iter;
+ BMFace *f = NULL;
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ found = true;
+ break;
+ }
}
- }
- BLI_assert(found);
+ BLI_assert(found || f == NULL);
#if 1
- /* total freak stuff, check if node exists somewhere else */
- /* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
- if ((n != n_other) && (n_other->bm_unique_verts)) {
- BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ /* total freak stuff, check if node exists somewhere else */
+ /* Slow */
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n_other = &bvh->nodes[i];
+ if ((n != n_other) && (n_other->bm_unique_verts)) {
+ BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ }
}
- }
#endif
+ }
}
#if 0
@@ -2049,7 +2239,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(!BM_vert_face_check(v));
+ /* this happens sometimes and seems harmless */
+ // BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 4d2307c3e12..19d3b31bd31 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -83,12 +83,11 @@ struct PBVHNode {
* array. The array is sized to match 'totprim', and each of
* the face's corners gets an index into the vert_indices
* array, in the same order as the corners in the original
- * MFace. The fourth value should not be used if the original
- * face is a triangle.
+ * MLoopTri.
*
* Used for leaf nodes in a mesh-based PBVH (not multires.)
*/
- const int (*face_vert_indices)[4];
+ const int (*face_vert_indices)[3];
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 4a649c2ea6d..572d23b39c7 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -150,7 +150,7 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-Scene *BKE_scene_copy(Scene *sce, int type)
+Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
@@ -161,7 +161,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (type == SCE_COPY_EMPTY) {
ListBase rl, rv;
/* XXX. main should become an arg */
- scen = BKE_scene_add(G.main, sce->id.name + 2);
+ scen = BKE_scene_add(bmain, sce->id.name + 2);
rl = scen->r.layers;
rv = scen->r.views;
@@ -182,10 +182,10 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BKE_sound_destroy_scene(scen);
}
else {
- scen = BKE_libblock_copy(&sce->id);
+ scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base));
- BKE_main_id_clear_newpoins(G.main);
+ BKE_main_id_clear_newpoins(bmain);
id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set);
@@ -209,7 +209,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (sce->nodetree) {
/* ID's are managed on both copy and switch */
- scen->nodetree = ntreeCopyTree(sce->nodetree);
+ scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
}
@@ -237,7 +237,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
id_us_plus((ID *)lineset->linestyle);
- lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
}
}
@@ -319,7 +319,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (type == SCE_COPY_FULL) {
if (scen->world) {
id_us_plus((ID *)scen->world);
- scen->world = BKE_world_copy(scen->world);
+ scen->world = BKE_world_copy(bmain, scen->world);
BKE_animdata_copy_id_action((ID *)scen->world);
}
@@ -333,7 +333,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
/* grease pencil */
if (scen->gpd) {
if (type == SCE_COPY_FULL) {
- scen->gpd = gpencil_data_duplicate(scen->gpd, false);
+ scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false);
}
else if (type == SCE_COPY_EMPTY) {
scen->gpd = NULL;
@@ -343,9 +343,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
}
}
- if (sce->preview) {
- scen->preview = BKE_previewimg_copy(sce->preview);
- }
+ scen->preview = BKE_previewimg_copy(sce->preview);
return scen;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 25b32cc40aa..fc3daa132c6 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -2243,7 +2243,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
.. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/
/* rule we never alter free variables :bp->vec bp->pos in here !
- * this will ruin adaptive stepsize AKA heun! (BM)
+ * this will ruin adaptive stepsize AKA heun! (BM)
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
BodyPoint *bp;
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index e5075a2d382..a91d8657179 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -34,6 +34,8 @@
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_speaker.h"
@@ -66,30 +68,25 @@ void *BKE_speaker_add(Main *bmain, const char *name)
return spk;
}
-Speaker *BKE_speaker_copy(Speaker *spk)
+Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
{
Speaker *spkn;
- spkn = BKE_libblock_copy(&spk->id);
+ spkn = BKE_libblock_copy(bmain, &spk->id);
+
if (spkn->sound)
id_us_plus(&spkn->sound->id);
- if (spk->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(spk)) {
+ BKE_id_expand_local(&spkn->id);
BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id);
}
return spkn;
}
-static void extern_local_speaker(Speaker *spk)
-{
- id_lib_extern((ID *)spk->sound);
-}
-
-void BKE_speaker_make_local(Speaker *spk)
+void BKE_speaker_make_local(Main *bmain, Speaker *spk)
{
- Main *bmain = G.main;
- Object *ob;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
@@ -97,44 +94,23 @@ void BKE_speaker_make_local(Speaker *spk)
* - mixed: make copy
*/
- if (spk->id.lib == NULL) return;
- if (spk->id.us == 1) {
- id_clear_lib_data(bmain, &spk->id);
- extern_local_speaker(spk);
+ if (!ID_IS_LINKED_DATABLOCK(spk)) {
return;
}
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == spk) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
+ BKE_library_ID_test_usages(bmain, spk, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &spk->id);
+ BKE_id_expand_local(&spk->id);
}
- ob = ob->id.next;
- }
+ else {
+ Speaker *spk_new = BKE_speaker_copy(bmain, spk);
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &spk->id);
- extern_local_speaker(spk);
- }
- else if (is_local && is_lib) {
- Speaker *spk_new = BKE_speaker_copy(spk);
- spk_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, spk->id.lib, &spk_new->id);
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == spk) {
-
- if (ob->id.lib == NULL) {
- ob->data = spk_new;
- id_us_plus(&spk_new->id);
- id_us_min(&spk->id);
- }
- }
- ob = ob->id.next;
+ spk_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, spk, spk_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index fdc2edba57f..269d6d32b31 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -452,7 +452,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
Text *tan;
TextLine *line, *tmp;
- tan = BKE_libblock_copy(&ta->id);
+ tan = BKE_libblock_copy(bmain, &ta->id);
/* file name can be NULL */
if (ta->name) {
@@ -491,7 +491,8 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
init_undo_text(tan);
- if (ta->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ta)) {
+ BKE_id_expand_local(&tan->id);
BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id);
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 3e4f13a2c8f..dcd60aaa702 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -58,6 +58,8 @@
#include "BKE_main.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_texture.h"
@@ -843,11 +845,11 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
/* ------------------------------------------------------------------------- */
-Tex *BKE_texture_copy(Tex *tex)
+Tex *BKE_texture_copy(Main *bmain, Tex *tex)
{
Tex *texn;
- texn = BKE_libblock_copy(&tex->id);
+ texn = BKE_libblock_copy(bmain, &tex->id);
if (BKE_texture_is_image_user(tex)) {
id_us_plus((ID *)texn->ima);
}
@@ -866,11 +868,14 @@ Tex *BKE_texture_copy(Tex *tex)
if (tex->nodetree->execdata) {
ntreeTexEndExecTree(tex->nodetree->execdata);
}
- texn->nodetree = ntreeCopyTree(tex->nodetree);
+ texn->nodetree = ntreeCopyTree(bmain, tex->nodetree);
}
- if (tex->id.lib) {
- BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id);
+ texn->preview = BKE_previewimg_copy(tex->preview);
+
+ if (ID_IS_LINKED_DATABLOCK(tex)) {
+ BKE_id_expand_local(&texn->id);
+ BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id);
}
return texn;
@@ -912,169 +917,32 @@ Tex *BKE_texture_localize(Tex *tex)
/* ------------------------------------------------------------------------- */
-static void extern_local_texture(Tex *tex)
+void BKE_texture_make_local(Main *bmain, Tex *tex)
{
- id_lib_extern((ID *)tex->ima);
-}
-
-void BKE_texture_make_local(Tex *tex)
-{
- Main *bmain = G.main;
- Material *ma;
- World *wrld;
- Lamp *la;
- Brush *br;
- FreestyleLineStyle *ls;
- int a;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (tex->id.lib == NULL) return;
- if (tex->id.us == 1) {
- id_clear_lib_data(bmain, &tex->id);
- extern_local_texture(tex);
+ if (!ID_IS_LINKED_DATABLOCK(tex)) {
return;
}
-
- ma = bmain->mat.first;
- while (ma) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
- if (ma->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- ma = ma->id.next;
- }
- la = bmain->lamp.first;
- while (la) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a] && la->mtex[a]->tex == tex) {
- if (la->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- la = la->id.next;
- }
- wrld = bmain->world.first;
- while (wrld) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
- if (wrld->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- wrld = wrld->id.next;
- }
- br = bmain->brush.first;
- while (br) {
- if (br->mtex.tex == tex) {
- if (br->id.lib) is_lib = true;
- else is_local = true;
- }
- if (br->mask_mtex.tex == tex) {
- if (br->id.lib) is_lib = true;
- else is_local = true;
- }
- br = br->id.next;
- }
- ls = bmain->linestyle.first;
- while (ls) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
- if (ls->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- ls = ls->id.next;
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &tex->id);
- extern_local_texture(tex);
- }
- else if (is_local && is_lib) {
- Tex *tex_new = BKE_texture_copy(tex);
- tex_new->id.us = 0;
+ BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib);
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, tex->id.lib, &tex_new->id);
-
- ma = bmain->mat.first;
- while (ma) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
- if (ma->id.lib == NULL) {
- ma->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- ma = ma->id.next;
- }
- la = bmain->lamp.first;
- while (la) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a] && la->mtex[a]->tex == tex) {
- if (la->id.lib == NULL) {
- la->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- la = la->id.next;
- }
- wrld = bmain->world.first;
- while (wrld) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
- if (wrld->id.lib == NULL) {
- wrld->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- wrld = wrld->id.next;
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &tex->id);
+ BKE_id_expand_local(&tex->id);
}
- br = bmain->brush.first;
- while (br) {
- if (br->mtex.tex == tex) {
- if (br->id.lib == NULL) {
- br->mtex.tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- if (br->mask_mtex.tex == tex) {
- if (br->id.lib == NULL) {
- br->mask_mtex.tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- br = br->id.next;
- }
- ls = bmain->linestyle.first;
- while (ls) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
- if (ls->id.lib == NULL) {
- ls->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- ls = ls->id.next;
+ else {
+ Tex *tex_new = BKE_texture_copy(bmain, tex);
+
+ tex_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index ec021586be5..9795a8174f8 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -46,6 +46,8 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_world.h"
@@ -117,12 +119,12 @@ World *add_world(Main *bmain, const char *name)
return wrld;
}
-World *BKE_world_copy(World *wrld)
+World *BKE_world_copy(Main *bmain, World *wrld)
{
World *wrldn;
int a;
- wrldn = BKE_libblock_copy(&wrld->id);
+ wrldn = BKE_libblock_copy(bmain, &wrld->id);
for (a = 0; a < MAX_MTEX; a++) {
if (wrld->mtex[a]) {
@@ -133,16 +135,16 @@ World *BKE_world_copy(World *wrld)
}
if (wrld->nodetree) {
- wrldn->nodetree = ntreeCopyTree(wrld->nodetree);
+ wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree);
}
- if (wrld->preview)
- wrldn->preview = BKE_previewimg_copy(wrld->preview);
+ wrldn->preview = BKE_previewimg_copy(wrld->preview);
BLI_listbase_clear(&wrldn->gpumaterial);
- if (wrld->id.lib) {
- BKE_id_lib_local_paths(G.main, wrld->id.lib, &wrldn->id);
+ if (ID_IS_LINKED_DATABLOCK(wrld)) {
+ BKE_id_expand_local(&wrldn->id);
+ BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id);
}
return wrldn;
@@ -174,48 +176,32 @@ World *localize_world(World *wrld)
return wrldn;
}
-void BKE_world_make_local(World *wrld)
+void BKE_world_make_local(Main *bmain, World *wrld)
{
- Main *bmain = G.main;
- Scene *sce;
bool is_local = false, is_lib = false;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
-
- if (wrld->id.lib == NULL) return;
- if (wrld->id.us == 1) {
- id_clear_lib_data(bmain, &wrld->id);
+
+ if (!ID_IS_LINKED_DATABLOCK(wrld)) {
return;
}
-
- for (sce = bmain->scene.first; sce && ELEM(false, is_lib, is_local); sce = sce->id.next) {
- if (sce->world == wrld) {
- if (sce->id.lib) is_lib = true;
- else is_local = true;
+
+ BKE_library_ID_test_usages(bmain, wrld, &is_local, &is_lib);
+
+ if (is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &wrld->id);
+ BKE_id_expand_local(&wrld->id);
}
- }
+ else {
+ World *wrld_new = BKE_world_copy(bmain, wrld);
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &wrld->id);
- }
- else if (is_local && is_lib) {
- World *wrld_new = BKE_world_copy(wrld);
- wrld_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrld_new->id);
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->world == wrld) {
- if (sce->id.lib == NULL) {
- sce->world = wrld_new;
- id_us_plus(&wrld_new->id);
- id_us_min(&wrld->id);
- }
- }
+ wrld_new->id.us = 0;
+
+ BKE_libblock_remap(bmain, wrld, wrld_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index fb8c2520e67..91d39801645 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -96,7 +96,8 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl
typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
/* callback must update nearest in case it finds a nearest result */
-typedef void (*BVHTree_NearestToRayCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeNearest *nearest);
+typedef void (*BVHTree_NearestToRayCallback)(void *userdata, const float ray_co[3], const float ray_dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest);
/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
@@ -142,8 +143,16 @@ int BLI_bvhtree_find_nearest(
BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
BVHTree_NearestPointCallback callback, void *userdata);
+int BLI_bvhtree_find_nearest_to_ray_angle(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata);
+
int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
BVHTree_NearestToRayCallback callback, void *userdata);
int BLI_bvhtree_ray_cast_ex(
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 54b824c91ac..84a25f533bf 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -115,6 +115,13 @@ float dist_signed_squared_to_corner_v3v3v3(
const float p[3],
const float v1[3], const float v2[3], const float v3[3],
const float axis_ref[3]);
+float dist_squared_to_ray_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float co[3], float *r_depth);
+float dist_squared_ray_to_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float r_point[3], float *r_depth);
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 8a36b047bad..d15fe1a95dc 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -191,6 +191,12 @@ MINLINE float len_manhattan_v3v3(const float a[3], const float b[3]) ATTR_WARN_U
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float normalize_v2_length(float r[2], const float unit_scale);
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
+MINLINE float normalize_v3_length(float r[3], const float unit_scale);
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
+MINLINE double normalize_v3_length_d(double n[3], const double unit_scale);
+
MINLINE float normalize_v2(float r[2]);
MINLINE float normalize_v2_v2(float r[2], const float a[2]);
MINLINE float normalize_v3(float r[3]);
@@ -215,6 +221,10 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
+void interp_v2_v2v2v2v2_cubic(
+ float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const float u);
+
void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const float t);
void interp_v3_v3v3_uchar(unsigned char target[3], const unsigned char a[3], const unsigned char b[3], const float t);
void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], const float t);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 6cef1924e33..92f4e998206 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -163,12 +163,23 @@ typedef struct BVHNearestRayData {
BVHTree *tree;
BVHTree_NearestToRayCallback callback;
void *userdata;
- BVHTreeRay ray;
- struct NearestRayToAABB_Precalc nearest_precalc;
+ struct {
+ bool sign[3];
+ float origin[3];
+ float direction[3];
+
+ float direction_scaled_square[3];
+ float inv_dir[3];
+
+ float cdot_axis[3];
+ } ray;
bool pick_smallest[3];
+
BVHTreeNearest nearest;
+
+ float scale[3];
} BVHNearestRayData;
/** \} */
@@ -1889,58 +1900,374 @@ void BLI_bvhtree_ray_cast_all(
/* -------------------------------------------------------------------- */
-/** \name BLI_bvhtree_find_nearest_to_ray
+/** \name BLI_bvhtree_find_nearest_to_ray functions
*
* \{ */
+static void dist_squared_ray_to_aabb_scaled_v3_precalc(
+ BVHNearestRayData *data,
+ const float ray_origin[3], const float ray_direction[3],
+ const bool ray_is_normalized, const float scale[3])
+{
+ if (scale) {
+ copy_v3_v3(data->scale, scale);
+ }
+ else {
+ copy_v3_fl(data->scale, 1.0f);
+ }
+ /* un-normalize ray */
+ if (ray_is_normalized && scale &&
+ (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f))
+ {
+ data->ray.direction[0] = ray_direction[0] * data->scale[0];
+ data->ray.direction[1] = ray_direction[1] * data->scale[1];
+ data->ray.direction[2] = ray_direction[2] * data->scale[2];
+
+ mul_v3_v3fl(data->ray.direction, ray_direction, 1 / len_v3(data->ray.direction));
+ }
+ else {
+ copy_v3_v3(data->ray.direction, ray_direction);
+ }
+
+ float dir_sq[3];
+
+ for (int i = 0; i < 3; i++) {
+ data->ray.origin[i] = ray_origin[i];
+ data->ray.inv_dir[i] = (data->ray.direction[i] != 0.0f) ?
+ (1.0f / data->ray.direction[i]) : FLT_MAX;
+ /* It has to be in function of `ray.inv_dir`,
+ * since the division of 1 by 0.0f, can be -inf or +inf */
+ data->ray.sign[i] = (data->ray.inv_dir[i] < 0.0f);
+
+ data->ray.direction_scaled_square[i] = data->ray.direction[i] * data->scale[i];
+
+ dir_sq[i] = SQUARE(data->ray.direction_scaled_square[i]);
+
+ data->ray.direction_scaled_square[i] *= data->scale[i];
+ }
+
+ /* `diag_sq` Length square of each face diagonal */
+ float diag_sq[3] = {
+ dir_sq[1] + dir_sq[2],
+ dir_sq[0] + dir_sq[2],
+ dir_sq[0] + dir_sq[1],
+ };
+
+ data->ray.cdot_axis[0] = (diag_sq[0] != 0.0f) ? data->ray.direction[0] / diag_sq[0] : FLT_MAX;
+ data->ray.cdot_axis[1] = (diag_sq[1] != 0.0f) ? data->ray.direction[1] / diag_sq[1] : FLT_MAX;
+ data->ray.cdot_axis[2] = (diag_sq[2] != 0.0f) ? data->ray.direction[2] / diag_sq[2] : FLT_MAX;
+}
+
+/**
+ * Returns the squared distance from a ray to a bound-box `AABB`.
+ * It is based on `fast_ray_nearest_hit` solution to obtain
+ * the coordinates of the nearest edge of Bound Box to the ray
+ */
+MINLINE float dist_squared_ray_to_aabb_scaled_v3__impl(
+ const BVHNearestRayData *data,
+ const float bv[6], float *r_depth_sq, bool r_axis_closest[3])
+{
+
+ /* `tmin` is a vector that has the smaller distances to each of the
+ * infinite planes of the `AABB` faces (hit in nearest face X plane,
+ * nearest face Y plane and nearest face Z plane) */
+ float local_bvmin[3], local_bvmax[3];
+
+ if (data->ray.sign[0]) {
+ local_bvmin[0] = bv[1];
+ local_bvmax[0] = bv[0];
+ }
+ else {
+ local_bvmin[0] = bv[0];
+ local_bvmax[0] = bv[1];
+ }
+
+ if (data->ray.sign[1]) {
+ local_bvmin[1] = bv[3];
+ local_bvmax[1] = bv[2];
+ }
+ else {
+ local_bvmin[1] = bv[2];
+ local_bvmax[1] = bv[3];
+ }
+
+ if (data->ray.sign[2]) {
+ local_bvmin[2] = bv[5];
+ local_bvmax[2] = bv[4];
+ }
+ else {
+ local_bvmin[2] = bv[4];
+ local_bvmax[2] = bv[5];
+ }
+
+ sub_v3_v3(local_bvmin, data->ray.origin);
+ sub_v3_v3(local_bvmax, data->ray.origin);
+
+ const float tmin[3] = {
+ local_bvmin[0] * data->ray.inv_dir[0],
+ local_bvmin[1] * data->ray.inv_dir[1],
+ local_bvmin[2] * data->ray.inv_dir[2],
+ };
+
+ /* `tmax` is a vector that has the longer distances to each of the
+ * infinite planes of the `AABB` faces (hit in farthest face X plane,
+ * farthest face Y plane and farthest face Z plane) */
+ const float tmax[3] = {
+ local_bvmax[0] * data->ray.inv_dir[0],
+ local_bvmax[1] * data->ray.inv_dir[1],
+ local_bvmax[2] * data->ray.inv_dir[2],
+ };
+ /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/
+ float v1[3], v2[3];
+ /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin)
+ * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/
+ float rtmin, rtmax, mul;
+ /* `main_axis` is the axis equivalent to edge close to the ray */
+ int main_axis;
+
+ r_axis_closest[0] = false;
+ r_axis_closest[1] = false;
+ r_axis_closest[2] = false;
+
+ /* *** min_axis_v3(tmax) *** */
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ // printf("# Hit in X %s\n", data->sign[0] ? "min", "max");
+ rtmax = tmax[0];
+ v1[0] = v2[0] = local_bvmax[0];
+ mul = local_bvmax[0] * data->ray.direction_scaled_square[0];
+ main_axis = 3;
+ r_axis_closest[0] = data->ray.sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max");
+ rtmax = tmax[1];
+ v1[1] = v2[1] = local_bvmax[1];
+ mul = local_bvmax[1] * data->ray.direction_scaled_square[1];
+ main_axis = 2;
+ r_axis_closest[1] = data->ray.sign[1];
+ }
+ else {
+ // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max");
+ rtmax = tmax[2];
+ v1[2] = v2[2] = local_bvmax[2];
+ mul = local_bvmax[2] * data->ray.direction_scaled_square[2];
+ main_axis = 1;
+ r_axis_closest[2] = data->ray.sign[2];
+ }
+
+ /* *** max_axis_v3(tmin) *** */
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ // printf("# To X %s\n", data->sign[0] ? "max", "min");
+ rtmin = tmin[0];
+ v1[0] = v2[0] = local_bvmin[0];
+ mul += local_bvmin[0] * data->ray.direction_scaled_square[0];
+ main_axis -= 3;
+ r_axis_closest[0] = !data->ray.sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ // printf("# To Y %s\n", data->sign[1] ? "max", "min");
+ rtmin = tmin[1];
+ v1[1] = v2[1] = local_bvmin[1];
+ mul += local_bvmin[1] * data->ray.direction_scaled_square[1];
+ main_axis -= 1;
+ r_axis_closest[1] = !data->ray.sign[1];
+ }
+ else {
+ // printf("# To Z %s\n", data->sign[2] ? "max", "min");
+ rtmin = tmin[2];
+ v1[2] = v2[2] = local_bvmin[2];
+ mul += local_bvmin[2] * data->ray.direction_scaled_square[2];
+ main_axis -= 2;
+ r_axis_closest[2] = !data->ray.sign[2];
+ }
+ /* *** end min/max axis *** */
+
+ if (main_axis < 0)
+ main_axis += 3;
+
+ /* if rtmin < rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmax < depth_min`, the whole `AABB` is behind us */
+ if (rtmax < min_depth) {
+ return fallback;
+ }
+#endif
+ const float proj = rtmin * data->ray.direction[main_axis];
+
+ if (data->ray.sign[main_axis])
+ r_axis_closest[main_axis] = (proj - local_bvmax[main_axis]) < (local_bvmin[main_axis] - proj);
+ else
+ r_axis_closest[main_axis] = (proj - local_bvmin[main_axis]) < (local_bvmax[main_axis] - proj);
+
+ //if (r_depth_sq)
+ // *r_depth_sq = SQUARE(rtmin);
+
+ return 0.0f;
+ }
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmin < depth_min`, the whole `AABB` is behing us */
+ else if (rtmin < min_depth) {
+ return fallback;
+ }
+#endif
+
+ if (data->ray.sign[main_axis]) {
+ v1[main_axis] = local_bvmax[main_axis];
+ v2[main_axis] = local_bvmin[main_axis];
+ }
+ else {
+ v1[main_axis] = local_bvmin[main_axis];
+ v2[main_axis] = local_bvmax[main_axis];
+ }
+ {
+ /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
+ const float proj = mul * data->ray.cdot_axis[main_axis];
+ float depth_sq, r_point[3];
+ if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
+ r_axis_closest[main_axis] = true;
+ /* `depth` is equivalent the distance of the the projection of v1 on the ray */
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v1[main_axis];
+
+ copy_v3_v3(r_point, v1);
+ }
+ else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
+ r_axis_closest[main_axis] = false;
+
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v2[main_axis];
+
+ copy_v3_v3(r_point, v2);
+ }
+ else { /* the nearest point of the ray is on the edge of the `AABB`. */
+ r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
+
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * proj;
+#if 0
+ r_point[0] = main_axis == 0 ? proj : v2[0];
+ r_point[1] = main_axis == 1 ? proj : v2[1];
+ r_point[2] = main_axis == 2 ? proj : v2[2];
+#else
+ v2[main_axis] = proj;
+ copy_v3_v3(r_point, v2);
+#endif
+ }
+ depth_sq *= depth_sq;
+
+ if (r_depth_sq)
+ *r_depth_sq = depth_sq;
+
+ /* TODO: scale can be optional */
+ r_point[0] *= data->scale[0];
+ r_point[1] *= data->scale[1];
+ r_point[2] *= data->scale[2];
+
+ return len_squared_v3(r_point) - depth_sq;
+ }
+}
+
+/**
+ * <pre>
+ * + r_point
+ * |
+ * | dist
+ * |
+ * +----depth----+orig <-- dir
+ *
+ * tangent = dist/depth
+ * </pre>
+ */
+static float calc_tangent_sq(BVHNearestRayData *data, BVHNode *node)
+{
+ float depth_sq;
+ const float dist_sq = dist_squared_ray_to_aabb_scaled_v3__impl(
+ data, node->bv, &depth_sq, data->pick_smallest);
+
+ return (dist_sq != 0.0f) ? (dist_sq / depth_sq) : 0.0f;
+}
+
static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node)
{
- const float *bv = node->bv;
- const float bb_min[3] = {bv[0], bv[2], bv[4]};
- const float bb_max[3] = {bv[1], bv[3], bv[5]};
- return dist_squared_ray_to_aabb_v3(&data->nearest_precalc, bb_min, bb_max, data->pick_smallest);
+ return dist_squared_ray_to_aabb_scaled_v3__impl(
+ data, node->bv, NULL,
+ data->pick_smallest);
}
-static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
+static void dfs_find_lowest_tangent_dfs(BVHNearestRayData *data, BVHNode *node)
{
if (node->totnode == 0) {
if (data->callback) {
- data->callback(data->userdata, node->index, &data->ray, &data->nearest);
+ data->callback(data->userdata, data->ray.origin, data->ray.direction,
+ data->scale, node->index, &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = calc_tangent_sq(data, node);
+ /* TODO: return a value to the data->nearest.co
+ * not urgent however since users currently define own callbacks */
+ }
+ }
+ else {
+ int i;
+ /* First pick the closest node to dive on */
+ if (data->pick_smallest[node->main_axis]) {
+ for (i = 0; i != node->totnode; i++) {
+ if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_lowest_tangent_dfs(data, node->children[i]);
+ }
+ }
}
else {
- const float dist_sq = calc_dist_sq_to_ray(data, node);
- if (dist_sq != FLT_MAX) { /* not an invalid ray */
- data->nearest.index = node->index;
- data->nearest.dist_sq = dist_sq;
- /* TODO: return a value to the data->nearest.co
- * not urgent however since users currently define own callbacks */
+ for (i = node->totnode - 1; i >= 0; i--) {
+ if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_lowest_tangent_dfs(data, node->children[i]);
+ }
}
}
}
+}
+
+static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->callback(data->userdata, data->ray.origin, data->ray.direction,
+ data->scale, node->index, &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = calc_dist_sq_to_ray(data, node);
+ /* TODO: return a value to the data->nearest.co
+ * not urgent however since users currently define own callbacks */
+ }
+ }
else {
int i;
/* First pick the closest node to dive on */
if (data->pick_smallest[node->main_axis]) {
for (i = 0; i != node->totnode; i++) {
- if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
- continue;
+ if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
}
else {
for (i = node->totnode - 1; i >= 0; i--) {
- if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
- continue;
+ if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
}
}
}
-int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+/**
+ * Returns the point whose tangent defined by the angle between the point and ray is the lowest
+ * nearest.dist_sq returns the angle's tangent
+ */
+int BLI_bvhtree_find_nearest_to_ray_angle(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
BVHTree_NearestToRayCallback callback, void *userdata)
{
BVHNearestRayData data;
@@ -1951,11 +2278,46 @@ int BLI_bvhtree_find_nearest_to_ray(
data.callback = callback;
data.userdata = userdata;
- copy_v3_v3(data.ray.origin, co);
- copy_v3_v3(data.ray.direction, dir);
- data.ray.radius = 0.0f; /* unused here */
+ dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
+
+ if (nearest) {
+ memcpy(&data.nearest, nearest, sizeof(*nearest));
+ }
+ else {
+ data.nearest.index = -1;
+ data.nearest.dist_sq = FLT_MAX;
+ }
+
+ /* dfs search */
+ if (root) {
+ if (calc_tangent_sq(&data, root) < data.nearest.dist_sq)
+ dfs_find_lowest_tangent_dfs(&data, root);
+ }
+
+ /* copy back results */
+ if (nearest) {
+ memcpy(nearest, &data.nearest, sizeof(*nearest));
+ }
+
+ return data.nearest.index;
+}
+
+/* return the nearest point to ray */
+int BLI_bvhtree_find_nearest_to_ray(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata)
+{
+ BVHNearestRayData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ data.tree = tree;
+
+ data.callback = callback;
+ data.userdata = userdata;
- dist_squared_ray_to_aabb_v3_precalc(&data.nearest_precalc, co, dir);
+ dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
if (nearest) {
memcpy(&data.nearest, nearest, sizeof(*nearest));
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index 33565596c1f..6000c1a680c 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -249,7 +249,7 @@ typedef struct BArrayMemory {
/**
* Main storage for all states
*/
-typedef struct BArrayStore {
+struct BArrayStore {
/* static */
BArrayInfo info;
@@ -260,7 +260,7 @@ typedef struct BArrayStore {
* #BArrayState may be in any order (logic should never depend on state order).
*/
ListBase states;
-} BArrayStore;
+};
/**
* A single instance of an array.
@@ -272,13 +272,13 @@ typedef struct BArrayStore {
* While this could be moved to a memory pool,
* it makes it easier to trace invalid usage, so leave as-is for now.
*/
-typedef struct BArrayState {
+struct BArrayState {
/** linked list in #BArrayStore.states */
struct BArrayState *next, *prev;
struct BChunkList *chunk_list; /* BChunkList's */
-} BArrayState;
+};
typedef struct BChunkList {
ListBase chunk_refs; /* BChunkRef's */
@@ -1750,10 +1750,11 @@ bool BLI_array_store_is_valid(
} \
} ((void)0)
-
/* count chunk_list's */
- int totrefs = 0;
GHash *chunk_list_map = BLI_ghash_ptr_new(__func__);
+ GHash *chunk_map = BLI_ghash_ptr_new(__func__);
+
+ int totrefs = 0;
for (BArrayState *state = bs->states.first; state; state = state->next) {
GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list);
}
@@ -1771,7 +1772,6 @@ bool BLI_array_store_is_valid(
}
/* count chunk's */
- GHash *chunk_map = BLI_ghash_ptr_new(__func__);
GHASH_ITER (gh_iter, chunk_list_map) {
const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 82f527942e8..40454a93ec8 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -572,6 +572,67 @@ float dist_signed_squared_to_corner_v3v3v3(
}
}
+/**
+ * return the distance squared of a point to a ray.
+ */
+float dist_squared_to_ray_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float co[3], float *r_depth)
+{
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_origin);
+ *r_depth = dot_v3v3(dvec, ray_direction);
+ return len_squared_v3(dvec) - SQUARE(*r_depth);
+}
+/**
+ * Find the closest point in a seg to a ray and return the distance squared.
+ * \param r_point : Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel).
+ * \param depth: the distance of r_point projection on ray to the ray_origin.
+ */
+float dist_squared_ray_to_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float r_point[3], float *r_depth)
+{
+ float a[3], t[3], n[3], lambda;
+ sub_v3_v3v3(a, v1, v0);
+ sub_v3_v3v3(t, v0, ray_origin);
+ cross_v3_v3v3(n, a, ray_direction);
+ const float nlen = len_squared_v3(n);
+
+ /* if (nlen == 0.0f) the lines are parallel,
+ * has no nearest point, only distance squared.*/
+ if (nlen == 0.0f) {
+ /* Calculate the distance to the point v0 then */
+ copy_v3_v3(r_point, v0);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else {
+ float c[3], cray[3];
+ sub_v3_v3v3(c, n, t);
+ cross_v3_v3v3(cray, c, ray_direction);
+ lambda = dot_v3v3(cray, n) / nlen;
+ if (lambda <= 0) {
+ copy_v3_v3(r_point, v0);
+
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else if (lambda >= 1) {
+ copy_v3_v3(r_point, v1);
+
+ sub_v3_v3v3(t, v1, ray_origin);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else {
+ madd_v3_v3v3fl(r_point, v0, a, lambda);
+
+ sub_v3_v3v3(t, r_point, ray_origin);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ }
+ return len_squared_v3(t) - SQUARE(*r_depth);
+}
+
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
*
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 069d23e7147..8c361673715 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -284,16 +284,19 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
if (x1 < 0) x1 = width - 1;
if (x2 >= width) x2 = 0;
}
+ else if (x2 < 0 || x1 >= width) {
+ copy_vn_fl(float_output, components, 0.0f);
+ return;
+ }
+
if (wrap_y) {
if (y1 < 0) y1 = height - 1;
if (y2 >= height) y2 = 0;
}
-
- CLAMP(x1, 0, width - 1);
- CLAMP(x2, 0, width - 1);
-
- CLAMP(y1, 0, height - 1);
- CLAMP(y2, 0, height - 1);
+ else if (y2 < 0 || y1 >= height) {
+ copy_vn_fl(float_output, components, 0.0f);
+ return;
+ }
/* sample including outside of edges of image */
if (x1 < 0 || y1 < 0) row1 = empty;
@@ -331,8 +334,21 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
const unsigned char *row1, *row2, *row3, *row4;
unsigned char empty[4] = {0, 0, 0, 0};
- /* sample area entirely outside image? */
- if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
+ /* pixel value must be already wrapped, however values at boundaries may flip */
+ if (wrap_x) {
+ if (x1 < 0) x1 = width - 1;
+ if (x2 >= width) x2 = 0;
+ }
+ else if (x2 < 0 || x1 >= width) {
+ copy_vn_uchar(byte_output, components, 0);
+ return;
+ }
+
+ if (wrap_y) {
+ if (y1 < 0) y1 = height - 1;
+ if (y2 >= height) y2 = 0;
+ }
+ else if (y2 < 0 || y1 >= height) {
copy_vn_uchar(byte_output, components, 0);
return;
}
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index d962e4f0fa7..b285a74b8ac 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -200,8 +200,7 @@ void mul_fac_qt_fl(float q[4], const float fac)
const float co = cosf(angle);
const float si = sinf(angle);
q[0] = co;
- normalize_v3(q + 1);
- mul_v3_fl(q + 1, si);
+ normalize_v3_length(q + 1, si);
}
/* skip error check, currently only needed by mat3_to_quat_is_ok */
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 988034349e0..95d5c9fde87 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -164,6 +164,27 @@ void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[
}
}
+/** \name Cubic curve interpolation (bezier spline).
+ * \{ */
+
+void interp_v2_v2v2v2v2_cubic(
+ float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const float u)
+{
+ float q0[2], q1[2], q2[2], r0[2], r1[2];
+
+ interp_v2_v2v2(q0, v1, v2, u);
+ interp_v2_v2v2(q1, v2, v3, u);
+ interp_v2_v2v2(q2, v3, v4, u);
+
+ interp_v2_v2v2(r0, q0, q1, u);
+ interp_v2_v2v2(r1, q1, q2, u);
+
+ interp_v2_v2v2(p, r0, r1, u);
+}
+
+/** \} */
+
/* weight 3 vectors,
* 'w' must be unit length but is not a vector, just 3 weights */
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index fd9f3d5ff99..e9fb77f6302 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -859,13 +859,13 @@ MINLINE float len_v3v3(const float a[3], const float b[3])
return len_v3(d);
}
-MINLINE float normalize_v2_v2(float r[2], const float a[2])
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
if (d > 1.0e-35f) {
d = sqrtf(d);
- mul_v2_v2fl(r, a, 1.0f / d);
+ mul_v2_v2fl(r, a, unit_length / d);
}
else {
zero_v2(r);
@@ -874,13 +874,22 @@ MINLINE float normalize_v2_v2(float r[2], const float a[2])
return d;
}
+MINLINE float normalize_v2_v2(float r[2], const float a[2])
+{
+ return normalize_v2_v2_length(r, a, 1.0f);
+}
MINLINE float normalize_v2(float n[2])
{
return normalize_v2_v2(n, n);
}
-MINLINE float normalize_v3_v3(float r[3], const float a[3])
+MINLINE float normalize_v2_length(float n[2], const float unit_length)
+{
+ return normalize_v2_v2_length(n, n, unit_length);
+}
+
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
@@ -888,7 +897,7 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3])
* scaled down models with camera extreme close */
if (d > 1.0e-35f) {
d = sqrtf(d);
- mul_v3_v3fl(r, a, 1.0f / d);
+ mul_v3_v3fl(r, a, unit_length / d);
}
else {
zero_v3(r);
@@ -897,8 +906,12 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3])
return d;
}
+MINLINE float normalize_v3_v3(float r[3], const float a[3])
+{
+ return normalize_v3_v3_length(r, a, 1.0f);
+}
-MINLINE double normalize_v3_d(double n[3])
+MINLINE double normalize_v3_length_d(double n[3], const double unit_length)
{
double d = n[0] * n[0] + n[1] * n[1] + n[2] * n[2];
@@ -908,7 +921,7 @@ MINLINE double normalize_v3_d(double n[3])
double mul;
d = sqrt(d);
- mul = 1.0 / d;
+ mul = unit_length / d;
n[0] *= mul;
n[1] *= mul;
@@ -921,6 +934,15 @@ MINLINE double normalize_v3_d(double n[3])
return d;
}
+MINLINE double normalize_v3_d(double n[3])
+{
+ return normalize_v3_length_d(n, 1.0);
+}
+
+MINLINE float normalize_v3_length(float n[3], const float unit_length)
+{
+ return normalize_v3_v3_length(n, n, unit_length);
+}
MINLINE float normalize_v3(float n[3])
{
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 82a92d3f654..5d0de6526b6 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -113,7 +113,6 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
@@ -916,7 +915,7 @@ static int read_file_dna(FileData *fd)
if (bhead->code == DNA1) {
const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
- fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+ fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap, true);
if (fd->filesdna) {
fd->compflags = DNA_struct_get_compareflags(fd->filesdna, fd->memsdna);
/* used to retrieve ID names from (bhead+1) */
@@ -1076,7 +1075,7 @@ static FileData *filedata_new(void)
* but it keeps us re-entrant, remove once we have
* a lib that provides a nice lock. - zr
*/
- fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+ fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
fd->datamap = oldnewmap_new();
fd->globmap = oldnewmap_new();
@@ -7896,9 +7895,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_260(fd, lib, main);
blo_do_versions_270(fd, lib, main);
- main->versionfile = BLENDER_VERSION;
- main->subversionfile = BLENDER_SUBVERSION;
-
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index d0dc9a88cc0..c191e48a143 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -80,20 +80,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-static int my_memcmp(const int *mem1, const int *mem2, const int len)
-{
- register int a = len;
- register const int *mema = mem1;
- register const int *memb = mem2;
-
- while (a--) {
- if (*mema != *memb) return 1;
- mema++;
- memb++;
- }
- return 0;
-}
-
void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
{
static MemFileChunk *compchunk = NULL;
@@ -118,7 +104,7 @@ void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsi
/* we compare compchunk with buf */
if (compchunk) {
if (compchunk->size == curchunk->size) {
- if (my_memcmp((int *)compchunk->buf, (const int *)buf, size / 4) == 0) {
+ if (memcmp(compchunk->buf, buf, size) == 0) {
curchunk->buf = compchunk->buf;
curchunk->ident = 1;
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 119754fe567..631aec545c2 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -1087,6 +1087,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
sce->gm.flag |= GAME_GLSL_NO_NODES;
if (fd->fileflags & G_FILE_GLSL_NO_EXTRA_TEX)
sce->gm.flag |= GAME_GLSL_NO_EXTRA_TEX;
+ if (fd->fileflags & G_FILE_GLSL_NO_ENV_LIGHTING)
+ sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING;
if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS)
sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 87fe6db96d0..9c7aa87f3cc 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -189,9 +189,9 @@
/* ********* my write, buffered writing with minimum size chunks ************ */
-#define MYWRITE_BUFFER_SIZE 100000
-#define MYWRITE_MAX_CHUNK 32768
-
+/* Use optimal allocation since blocks of this size are kept in memory for undo. */
+#define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17)) /* 128kb */
+#define MYWRITE_MAX_CHUNK (MEM_SIZE_OPTIMAL(1 << 15)) /* ~32kb */
/** \name Small API to handle compression.
@@ -323,7 +323,7 @@ static WriteData *writedata_new(WriteWrap *ww)
{
WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
- wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+ wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
wd->ww = ww;
@@ -364,26 +364,31 @@ static void writedata_free(WriteData *wd)
/***/
/**
+ * Flush helps the de-duplicating memory for undo-save by logically segmenting data,
+ * so differences in one part of memory won't cause unrelated data to be duplicated.
+ */
+static void mywrite_flush(WriteData *wd)
+{
+ if (wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count = 0;
+ }
+}
+
+/**
* Low level WRITE(2) wrapper that buffers data
* \param adr Pointer to new chunk of data
* \param len Length of new chunk of data
* \warning Talks to other functions with global parameters
*/
-
-#define MYWRITE_FLUSH NULL
-
static void mywrite(WriteData *wd, const void *adr, int len)
{
if (UNLIKELY(wd->error)) {
return;
}
- /* flush helps compression for undo-save */
- if (adr == MYWRITE_FLUSH) {
- if (wd->count) {
- writedata_do_write(wd, wd->buf, wd->count);
- wd->count = 0;
- }
+ if (adr == NULL) {
+ BLI_assert(0);
return;
}
@@ -814,8 +819,7 @@ static void write_actions(WriteData *wd, ListBase *idbase)
}
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_keyingsets(WriteData *wd, ListBase *list)
@@ -1666,8 +1670,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
ob = ob->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
@@ -1694,6 +1697,8 @@ static void write_vfonts(WriteData *wd, ListBase *idbase)
vf = vf->id.next;
}
+
+ mywrite_flush(wd);
}
@@ -1726,8 +1731,8 @@ static void write_keys(WriteData *wd, ListBase *idbase)
key = key->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_cameras(WriteData *wd, ListBase *idbase)
@@ -1829,8 +1834,7 @@ static void write_curves(WriteData *wd, ListBase *idbase)
cu = cu->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
@@ -2104,6 +2108,8 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
mesh = mesh->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_lattices(WriteData *wd, ListBase *idbase)
@@ -2130,6 +2136,8 @@ static void write_lattices(WriteData *wd, ListBase *idbase)
}
lt = lt->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_images(WriteData *wd, ListBase *idbase)
@@ -2173,8 +2181,8 @@ static void write_images(WriteData *wd, ListBase *idbase)
}
ima = ima->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_textures(WriteData *wd, ListBase *idbase)
@@ -2226,8 +2234,7 @@ static void write_textures(WriteData *wd, ListBase *idbase)
tex = tex->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_materials(WriteData *wd, ListBase *idbase)
@@ -2343,6 +2350,8 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
}
la = la->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
@@ -2589,8 +2598,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
sce = sce->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_gpencils(WriteData *wd, ListBase *lb)
@@ -2627,6 +2636,8 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
}
}
}
+
+ mywrite_flush(wd);
}
static void write_windowmanagers(WriteData *wd, ListBase *lb)
@@ -2643,6 +2654,10 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb)
writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
}
}
+
+ /* typically flushing wouldn't be needed however this data _always_ changes,
+ * so flush here for more efficient undo. */
+ mywrite_flush(wd);
}
static void write_region(WriteData *wd, ARegion *ar, int spacetype)
@@ -2682,43 +2697,43 @@ static void write_uilist(WriteData *wd, uiList *ui_list)
}
}
-static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list)
+static void write_soops(WriteData *wd, SpaceOops *so)
{
BLI_mempool *ts = so->treestore;
if (ts) {
+ SpaceOops so_flat = *so;
+
int elems = BLI_mempool_count(ts);
/* linearize mempool to array */
TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL;
if (data) {
- TreeStore *ts_flat = MEM_callocN(sizeof(TreeStore), "TreeStore");
+ /* In this block we use the memory location of the treestore
+ * but _not_ its data, the addresses in this case are UUID's,
+ * since we can't rely on malloc giving us different values each time.
+ */
+ TreeStore ts_flat = {0};
- ts_flat->usedelem = elems;
- ts_flat->totelem = elems;
- ts_flat->data = data;
+ /* we know the treestore is at least as big as a pointer,
+ * so offsetting works to give us a UUID. */
+ void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *));
+
+ ts_flat.usedelem = elems;
+ ts_flat.totelem = elems;
+ ts_flat.data = data_addr;
- /* temporarily replace mempool-treestore by flat-treestore */
- so->treestore = (BLI_mempool *)ts_flat;
writestruct(wd, DATA, SpaceOops, 1, so);
- writestruct(wd, DATA, TreeStore, 1, ts_flat);
- writestruct(wd, DATA, TreeStoreElem, elems, data);
+ writestruct_at_address(wd, DATA, TreeStore, 1, ts, &ts_flat);
+ writestruct_at_address(wd, DATA, TreeStoreElem, elems, data_addr, data);
- /* we do not free the pointers immediately, because if we have multiple
- * outliners in a screen we might get the same address on the next
- * malloc, which makes the address no longer unique and so invalid for
- * lookups on file read, causing crashes or double frees */
- BLI_linklist_prepend(tmp_mem_list, ts_flat);
- BLI_linklist_prepend(tmp_mem_list, data);
+ MEM_freeN(data);
}
else {
- so->treestore = NULL;
- writestruct(wd, DATA, SpaceOops, 1, so);
+ so_flat.treestore = NULL;
+ writestruct_at_address(wd, DATA, SpaceOops, 1, so, &so_flat);
}
-
- /* restore old treestore */
- so->treestore = ts;
}
else {
writestruct(wd, DATA, SpaceOops, 1, so);
@@ -2731,7 +2746,6 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
ScrArea *sa;
ScrVert *sv;
ScrEdge *se;
- LinkNode *tmp_mem_list = NULL;
sc = scrbase->first;
while (sc) {
@@ -2835,7 +2849,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
}
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so = (SpaceOops *)sl;
- write_soops(wd, so, &tmp_mem_list);
+ write_soops(wd, so);
}
else if (sl->spacetype == SPACE_IMAGE) {
writestruct(wd, DATA, SpaceImage, 1, sl);
@@ -2903,10 +2917,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
sc = sc->id.next;
}
- BLI_linklist_freeN(tmp_mem_list);
-
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_bone(WriteData *wd, Bone *bone)
@@ -2954,8 +2965,7 @@ static void write_armatures(WriteData *wd, ListBase *idbase)
arm = arm->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_texts(WriteData *wd, ListBase *idbase)
@@ -2996,8 +3006,7 @@ static void write_texts(WriteData *wd, ListBase *idbase)
text = text->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_speakers(WriteData *wd, ListBase *idbase)
@@ -3041,8 +3050,7 @@ static void write_sounds(WriteData *wd, ListBase *idbase)
sound = sound->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_groups(WriteData *wd, ListBase *idbase)
@@ -3065,6 +3073,8 @@ static void write_groups(WriteData *wd, ListBase *idbase)
}
}
}
+
+ mywrite_flush(wd);
}
static void write_nodetrees(WriteData *wd, ListBase *idbase)
@@ -3277,8 +3287,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase)
clip = clip->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_masks(WriteData *wd, ListBase *idbase)
@@ -3338,8 +3347,7 @@ static void write_masks(WriteData *wd, ListBase *idbase)
mask = mask->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
@@ -3688,6 +3696,8 @@ static void write_libraries(WriteData *wd, Main *main)
}
}
}
+
+ mywrite_flush(wd);
}
/* context is usually defined by WM, two cases where no WM is available:
@@ -3787,6 +3797,10 @@ static bool write_file_handle(
write_thumb(wd, thumb);
write_global(wd, write_flags, mainvar);
+ /* The windowmanager and screen often change,
+ * avoid thumbnail detecting changes because of this. */
+ mywrite_flush(wd);
+
write_windowmanagers(wd, &mainvar->wm);
write_screens(wd, &mainvar->screen);
write_movieclips(wd, &mainvar->movieclip);
@@ -3819,11 +3833,17 @@ static bool write_file_handle(
write_linestyles(wd, &mainvar->linestyle);
write_libraries(wd, mainvar->next);
+ /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
+ mywrite_flush(wd);
+
if (write_flags & G_FILE_USERPREFS) {
write_userdef(wd);
}
- /* dna as last, because (to be implemented) test for which structs are written */
+ /* Write DNA last, because (to be implemented) test for which structs are written.
+ *
+ * Note that we *borrow* the pointer to 'DNAstr',
+ * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */
writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
#ifdef USE_NODE_COMPAT_CUSTOMNODES
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index e3caeedd2c9..72ea7bd7f5d 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -89,7 +89,6 @@ BLI_STATIC_ASSERT((sizeof(BMHeader) <= 16), "BMHeader size has grown!");
typedef struct BMVert {
BMHeader head;
- struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
float co[3]; /* vertex coordinates */
float no[3]; /* vertex normal */
@@ -102,6 +101,11 @@ typedef struct BMVert {
struct BMEdge *e;
} BMVert;
+typedef struct BMVert_OFlag {
+ BMVert base;
+ struct BMFlagLayer *oflags;
+} BMVert_OFlag;
+
/* disk link structure, only used by edges */
typedef struct BMDiskLink {
struct BMEdge *next, *prev;
@@ -109,7 +113,6 @@ typedef struct BMDiskLink {
typedef struct BMEdge {
BMHeader head;
- struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
struct BMVert *v1, *v2; /* vertices (unordered) */
@@ -122,6 +125,11 @@ typedef struct BMEdge {
BMDiskLink v1_disk_link, v2_disk_link;
} BMEdge;
+typedef struct BMEdge_OFlag {
+ BMEdge base;
+ struct BMFlagLayer *oflags;
+} BMEdge_OFlag;
+
typedef struct BMLoop {
BMHeader head;
/* notice no flags layer */
@@ -142,10 +150,6 @@ typedef struct BMLoop {
/* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these don't have a flag layer */
typedef struct BMElemF {
BMHeader head;
-
- /* keep directly after header,
- * optional array of flags, only used by the operator stack */
- struct BMFlagLayer *oflags;
} BMElemF;
/* can cast anything to this, including BMLoop */
@@ -163,7 +167,6 @@ typedef struct BMLoopList {
typedef struct BMFace {
BMHeader head;
- struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */
#ifdef USE_BMESH_HOLES
int totbounds; /*total boundaries, is one plus the number of holes in the face*/
@@ -177,6 +180,11 @@ typedef struct BMFace {
// short _pad[3];
} BMFace;
+typedef struct BMFace_OFlag {
+ BMFace base;
+ struct BMFlagLayer *oflags;
+} BMFace_OFlag;
+
typedef struct BMFlagLayer {
short f; /* flags */
} BMFlagLayer;
@@ -217,6 +225,8 @@ typedef struct BMesh {
/* operator api stuff (must be all NULL or all alloc'd) */
struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool;
+ unsigned int use_toolflags : 1;
+
int toolflag_index;
struct BMOperator *currentop;
@@ -259,10 +269,12 @@ enum {
/* args for _Generic */
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
+ BMVert_OFlag *, BMEdge_OFlag *, BMFace_OFlag *, \
BMElem *, BMElemF *, BMHeader *
#define _BM_GENERIC_TYPE_ELEM_CONST \
const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \
+ const BMVert_OFlag *, const BMEdge_OFlag *, const BMFace_OFlag *, \
const BMElem *, const BMElemF *, const BMHeader *, \
void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \
BMElem * const, BMElemF * const, BMHeader * const
@@ -276,6 +288,27 @@ enum {
#define BM_CHECK_TYPE_ELEM(ele) \
CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST)
+/* vert */
+#define _BM_GENERIC_TYPE_VERT_NONCONST BMVert *, BMVert_OFlag *
+#define _BM_GENERIC_TYPE_VERT_CONST const BMVert *, const BMVert_OFlag *
+#define BM_CHECK_TYPE_VERT_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_CONST)
+#define BM_CHECK_TYPE_VERT_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_VERT(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_NONCONST, _BM_GENERIC_TYPE_VERT_CONST)
+/* edge */
+#define _BM_GENERIC_TYPE_EDGE_NONCONST BMEdge *, BMEdge_OFlag *
+#define _BM_GENERIC_TYPE_EDGE_CONST const BMEdge *, const BMEdge_OFlag *
+#define BM_CHECK_TYPE_EDGE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_CONST)
+#define BM_CHECK_TYPE_EDGE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_EDGE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_NONCONST, _BM_GENERIC_TYPE_EDGE_CONST)
+/* face */
+#define _BM_GENERIC_TYPE_FACE_NONCONST BMFace *, BMFace_OFlag *
+#define _BM_GENERIC_TYPE_FACE_CONST const BMFace *, const BMFace_OFlag *
+#define BM_CHECK_TYPE_FACE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_CONST)
+#define BM_CHECK_TYPE_FACE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_FACE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_NONCONST, _BM_GENERIC_TYPE_FACE_CONST)
+
+
+
/* Assignment from a void* to a typed pointer is not allowed in C++,
* casting the LHS to void works fine though.
*/
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index fdad93ee90d..4d92baab6eb 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -714,7 +714,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old);
/* allocate a bmesh */
- bm_new = BM_mesh_create(&allocsize);
+ bm_new = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = bm_old->use_toolflags,}));
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 1d68cdcf28a..e83b752947c 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -81,7 +81,9 @@ BMVert *BM_vert_create(
v->head.api_flag = 0;
/* allocate flags */
- v->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMVert_OFlag *)v)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ }
/* 'v->no' is handled by BM_elem_attrs_copy */
if (co) {
@@ -174,7 +176,9 @@ BMEdge *BM_edge_create(
e->head.api_flag = 0;
/* allocate flags */
- e->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMEdge_OFlag *)e)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ }
e->v1 = v1;
e->v2 = v2;
@@ -386,7 +390,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
f->head.api_flag = 0;
/* allocate flags */
- f->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMFace_OFlag *)f)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ }
#ifdef USE_BMESH_HOLES
BLI_listbase_clear(&f->loops);
@@ -758,7 +764,7 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v)
CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
if (bm->vtoolflagpool) {
- BLI_mempool_free(bm->vtoolflagpool, v->oflags);
+ BLI_mempool_free(bm->vtoolflagpool, ((BMVert_OFlag *)v)->oflags);
}
BLI_mempool_free(bm->vpool, v);
}
@@ -779,7 +785,7 @@ static void bm_kill_only_edge(BMesh *bm, BMEdge *e)
CustomData_bmesh_free_block(&bm->edata, &e->head.data);
if (bm->etoolflagpool) {
- BLI_mempool_free(bm->etoolflagpool, e->oflags);
+ BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)e)->oflags);
}
BLI_mempool_free(bm->epool, e);
}
@@ -803,7 +809,7 @@ static void bm_kill_only_face(BMesh *bm, BMFace *f)
CustomData_bmesh_free_block(&bm->pdata, &f->head.data);
if (bm->ftoolflagpool) {
- BLI_mempool_free(bm->ftoolflagpool, f->oflags);
+ BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags);
}
BLI_mempool_free(bm->fpool, f);
}
@@ -2196,7 +2202,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
/* deallocate edge and its two loops as well as f2 */
if (bm->etoolflagpool) {
- BLI_mempool_free(bm->etoolflagpool, l_f1->e->oflags);
+ BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags);
}
BLI_mempool_free(bm->epool, l_f1->e);
bm->totedge--;
@@ -2205,7 +2211,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
BLI_mempool_free(bm->lpool, l_f2);
bm->totloop--;
if (bm->ftoolflagpool) {
- BLI_mempool_free(bm->ftoolflagpool, f2->oflags);
+ BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags);
}
BLI_mempool_free(bm->fpool, f2);
bm->totface--;
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index 882d78ce6b3..1449a6ef9d7 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -54,7 +54,7 @@ static void bmo_remove_tagged_faces(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (f, f_next, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, oflag)) {
+ if (BMO_face_flag_test(bm, f, oflag)) {
BM_face_kill(bm, f);
}
}
@@ -66,7 +66,7 @@ static void bmo_remove_tagged_edges(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, oflag)) {
+ if (BMO_edge_flag_test(bm, e, oflag)) {
BM_edge_kill(bm, e);
}
}
@@ -78,7 +78,7 @@ static void bmo_remove_tagged_verts(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag)) {
+ if (BMO_vert_flag_test(bm, v, oflag)) {
BM_vert_kill(bm, v);
}
}
@@ -90,7 +90,7 @@ static void bmo_remove_tagged_verts_loose(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag) && (v->e == NULL)) {
+ if (BMO_vert_flag_test(bm, v, oflag) && (v->e == NULL)) {
BM_vert_kill(bm, v);
}
}
@@ -132,9 +132,9 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
/* flush down to vert */
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, oflag)) {
- BMO_elem_flag_enable(bm, e->v1, oflag);
- BMO_elem_flag_enable(bm, e->v2, oflag);
+ if (BMO_edge_flag_test(bm, e, oflag)) {
+ BMO_vert_flag_enable(bm, e->v1, oflag);
+ BMO_vert_flag_enable(bm, e->v2, oflag);
}
}
bmo_remove_tagged_edges(bm, oflag);
@@ -165,27 +165,27 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
/* go through and mark all edges and all verts of all faces for delete */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, oflag)) {
+ if (BMO_face_flag_test(bm, f, oflag)) {
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_enable(bm, l_iter->v, oflag);
- BMO_elem_flag_enable(bm, l_iter->e, oflag);
+ BMO_vert_flag_enable(bm, l_iter->v, oflag);
+ BMO_edge_flag_enable(bm, l_iter->e, oflag);
} while ((l_iter = l_iter->next) != l_first);
}
}
/* now go through and mark all remaining faces all edges for keeping */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag)) {
+ if (!BMO_face_flag_test(bm, f, oflag)) {
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_disable(bm, l_iter->v, oflag);
- BMO_elem_flag_disable(bm, l_iter->e, oflag);
+ BMO_vert_flag_disable(bm, l_iter->v, oflag);
+ BMO_edge_flag_disable(bm, l_iter->e, oflag);
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -195,13 +195,13 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
/* 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);
+ BMO_edge_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);
+ if (!BMO_edge_flag_test(bm, e, oflag)) {
+ BMO_vert_flag_disable(bm, e->v1, oflag);
+ BMO_vert_flag_disable(bm, e->v2, oflag);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index cc79e28a361..961b10d848a 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -339,16 +339,43 @@ int BMO_iter_elem_count_flag(
const short oflag, const bool value)
{
BMIter iter;
- BMElemF *ele;
int count = 0;
/* loops have no header flags */
BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP);
- BM_ITER_ELEM (ele, &iter, data, itype) {
- if (BMO_elem_flag_test_bool(bm, ele, oflag) == value) {
- count++;
+ switch (bm_iter_itype_htype_map[itype]) {
+ case BM_VERT:
+ {
+ BMVert *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
}
+ case BM_EDGE:
+ {
+ BMEdge *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ BMFace *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_face_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
+ }
+
}
return count;
}
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index d6ca7239e39..7178a8132d2 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -842,7 +842,7 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
/* the 2 vertex normals will be close but not at rightangles to the edge
* for rotate about edge we want them to be at right angles, so we need to
- * do some extra colculation to correct the vert normals,
+ * do some extra calculation to correct the vert normals,
* we need the plane for this */
cross_v3_v3v3(vec, r_normal, plane);
cross_v3_v3v3(r_normal, plane, vec);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ed1bd16b2e4..57a6d8d2e1a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -48,16 +48,52 @@
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
-static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize)
+static void bm_mempool_init_ex(
+ const BMAllocTemplate *allocsize, const bool use_toolflags,
+ BLI_mempool **r_vpool, BLI_mempool **r_epool, BLI_mempool **r_lpool, BLI_mempool **r_fpool)
{
- bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize->totvert,
- bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER);
- bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize->totedge,
- bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER);
- bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize->totloop,
- bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP);
- bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize->totface,
- bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER);
+ size_t vert_size, edge_size, loop_size, face_size;
+
+ if (use_toolflags == true) {
+ vert_size = sizeof(BMVert_OFlag);
+ edge_size = sizeof(BMEdge_OFlag);
+ loop_size = sizeof(BMLoop);
+ face_size = sizeof(BMFace_OFlag);
+ }
+ else {
+ vert_size = sizeof(BMVert);
+ edge_size = sizeof(BMEdge);
+ loop_size = sizeof(BMLoop);
+ face_size = sizeof(BMFace);
+ }
+
+ if (r_vpool) {
+ *r_vpool = BLI_mempool_create(
+ vert_size, allocsize->totvert,
+ bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER);
+ }
+ if (r_epool) {
+ *r_epool = BLI_mempool_create(
+ edge_size, allocsize->totedge,
+ bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER);
+ }
+ if (r_lpool) {
+ *r_lpool = BLI_mempool_create(
+ loop_size, allocsize->totloop,
+ bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP);
+ }
+ if (r_fpool) {
+ *r_fpool = BLI_mempool_create(
+ face_size, allocsize->totface,
+ bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER);
+ }
+}
+
+static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags)
+{
+ bm_mempool_init_ex(
+ allocsize, use_toolflags,
+ &bm->vpool, &bm->epool, &bm->lpool, &bm->fpool);
#ifdef USE_BMESH_HOLES
bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), 512, 512, BLI_MEMPOOL_NOP);
@@ -66,6 +102,8 @@ static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize)
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
+ BLI_assert(bm->use_toolflags);
+
if (bm->vtoolflagpool && bm->etoolflagpool && bm->ftoolflagpool) {
return;
}
@@ -80,7 +118,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->vtoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -89,7 +127,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->etoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -98,7 +136,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->ftoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -134,15 +172,18 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
*
* \note ob is needed by multires
*/
-BMesh *BM_mesh_create(const BMAllocTemplate *allocsize)
+BMesh *BM_mesh_create(
+ const BMAllocTemplate *allocsize,
+ const struct BMeshCreateParams *params)
{
/* allocate the structure */
BMesh *bm = MEM_callocN(sizeof(BMesh), __func__);
/* allocate the memory pools for the mesh elements */
- bm_mempool_init(bm, allocsize);
+ bm_mempool_init(bm, allocsize, params->use_toolflags);
/* allocate one flag pool that we don't get rid of. */
+ bm->use_toolflags = params->use_toolflags;
bm->toolflag_index = 0;
bm->totflags = 0;
@@ -239,13 +280,16 @@ void BM_mesh_data_free(BMesh *bm)
*/
void BM_mesh_clear(BMesh *bm)
{
+ const bool use_toolflags = bm->use_toolflags;
+
/* free old mesh */
BM_mesh_data_free(bm);
memset(bm, 0, sizeof(BMesh));
/* allocate the memory pools for the mesh elements */
- bm_mempool_init(bm, &bm_mesh_allocsize_default);
+ bm_mempool_init(bm, &bm_mesh_allocsize_default, use_toolflags);
+ bm->use_toolflags = use_toolflags;
bm->toolflag_index = 0;
bm->totflags = 0;
@@ -1706,3 +1750,262 @@ void BM_mesh_remap(
if (fptr_map)
BLI_ghash_free(fptr_map, NULL, NULL);
}
+
+/**
+ * Use new memory pools for this mesh.
+ *
+ * \note needed for re-sizing elements (adding/removing tool flags)
+ * but could also be used for packing fragmented bmeshes.
+ */
+void BM_mesh_rebuild(
+ BMesh *bm, const struct BMeshCreateParams *params,
+ BLI_mempool *vpool_dst, BLI_mempool *epool_dst, BLI_mempool *lpool_dst, BLI_mempool *fpool_dst)
+{
+ const char remap =
+ (vpool_dst ? BM_VERT : 0) |
+ (epool_dst ? BM_EDGE : 0) |
+ (lpool_dst ? BM_LOOP : 0) |
+ (fpool_dst ? BM_FACE : 0);
+
+ BMVert **vtable_dst = (remap & BM_VERT) ? MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__) : NULL;
+ BMEdge **etable_dst = (remap & BM_EDGE) ? MEM_mallocN(bm->totedge * sizeof(BMEdge *), __func__) : NULL;
+ BMLoop **ltable_dst = (remap & BM_LOOP) ? MEM_mallocN(bm->totloop * sizeof(BMLoop *), __func__) : NULL;
+ BMFace **ftable_dst = (remap & BM_FACE) ? MEM_mallocN(bm->totface * sizeof(BMFace *), __func__) : NULL;
+
+ const bool use_toolflags = params->use_toolflags;
+
+ if (remap & BM_VERT) {
+ BMIter iter;
+ int index;
+ BMVert *v_src;
+ BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, index) {
+ BMVert *v_dst = BLI_mempool_alloc(vpool_dst);
+ memcpy(v_dst, v_src, sizeof(BMVert));
+ if (use_toolflags) {
+ ((BMVert_OFlag *)v_dst)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ }
+
+ vtable_dst[index] = v_dst;
+ BM_elem_index_set(v_src, index); /* set_ok */
+ }
+ }
+
+ if (remap & BM_EDGE) {
+ BMIter iter;
+ int index;
+ BMEdge *e_src;
+ BM_ITER_MESH_INDEX (e_src, &iter, bm, BM_EDGES_OF_MESH, index) {
+ BMEdge *e_dst = BLI_mempool_alloc(epool_dst);
+ memcpy(e_dst, e_src, sizeof(BMEdge));
+ if (use_toolflags) {
+ ((BMEdge_OFlag *)e_dst)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ }
+
+ etable_dst[index] = e_dst;
+ BM_elem_index_set(e_src, index); /* set_ok */
+ }
+ }
+
+ if (remap & (BM_LOOP | BM_FACE)) {
+ BMIter iter;
+ int index, index_loop = 0;
+ BMFace *f_src;
+ BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, index) {
+
+ if (remap & BM_FACE) {
+ BMFace *f_dst = BLI_mempool_alloc(fpool_dst);
+ memcpy(f_dst, f_src, sizeof(BMFace));
+ if (use_toolflags) {
+ ((BMFace_OFlag *)f_dst)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ }
+
+ ftable_dst[index] = f_dst;
+ BM_elem_index_set(f_src, index); /* set_ok */
+ }
+
+ /* handle loops */
+ if (remap & BM_LOOP) {
+ BMLoop *l_iter_src, *l_first_src;
+ l_iter_src = l_first_src = BM_FACE_FIRST_LOOP((BMFace *)f_src);
+ do {
+ BMLoop *l_dst = BLI_mempool_alloc(lpool_dst);
+ memcpy(l_dst, l_iter_src, sizeof(BMLoop));
+ ltable_dst[index_loop] = l_dst;
+ BM_elem_index_set(l_iter_src, index_loop++); /* set_ok */
+ } while ((l_iter_src = l_iter_src->next) != l_first_src);
+ }
+ }
+ }
+
+#define MAP_VERT(ele) vtable_dst[BM_elem_index_get(ele)]
+#define MAP_EDGE(ele) etable_dst[BM_elem_index_get(ele)]
+#define MAP_LOOP(ele) ltable_dst[BM_elem_index_get(ele)]
+#define MAP_FACE(ele) ftable_dst[BM_elem_index_get(ele)]
+
+#define REMAP_VERT(ele) { if (remap & BM_VERT) { ele = MAP_VERT(ele); }} ((void)0)
+#define REMAP_EDGE(ele) { if (remap & BM_EDGE) { ele = MAP_EDGE(ele); }} ((void)0)
+#define REMAP_LOOP(ele) { if (remap & BM_LOOP) { ele = MAP_LOOP(ele); }} ((void)0)
+#define REMAP_FACE(ele) { if (remap & BM_FACE) { ele = MAP_FACE(ele); }} ((void)0)
+
+ /* verts */
+ {
+ for (int i = 0; i < bm->totvert; i++) {
+ BMVert *v = vtable_dst[i];
+ if (v->e) {
+ REMAP_EDGE(v->e);
+ }
+ }
+ }
+
+ /* edges */
+ {
+ for (int i = 0; i < bm->totedge; i++) {
+ BMEdge *e = etable_dst[i];
+ REMAP_VERT(e->v1);
+ REMAP_VERT(e->v2);
+ REMAP_EDGE(e->v1_disk_link.next);
+ REMAP_EDGE(e->v1_disk_link.prev);
+ REMAP_EDGE(e->v2_disk_link.next);
+ REMAP_EDGE(e->v2_disk_link.prev);
+ if (e->l) {
+ REMAP_LOOP(e->l);
+ }
+ }
+ }
+
+ /* faces */
+ {
+ for (int i = 0; i < bm->totface; i++) {
+ BMFace *f = ftable_dst[i];
+ REMAP_LOOP(f->l_first);
+
+ {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)f);
+ do {
+ REMAP_VERT(l_iter->v);
+ REMAP_EDGE(l_iter->e);
+ REMAP_FACE(l_iter->f);
+
+ REMAP_LOOP(l_iter->radial_next);
+ REMAP_LOOP(l_iter->radial_prev);
+ REMAP_LOOP(l_iter->next);
+ REMAP_LOOP(l_iter->prev);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ }
+
+ for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
+ switch (ese->htype) {
+ case BM_VERT:
+ if (remap & BM_VERT) {
+ ese->ele = (BMElem *)MAP_VERT(ese->ele);
+ }
+ break;
+ case BM_EDGE:
+ if (remap & BM_EDGE) {
+ ese->ele = (BMElem *)MAP_EDGE(ese->ele);
+ }
+ break;
+ case BM_FACE:
+ if (remap & BM_FACE) {
+ ese->ele = (BMElem *)MAP_FACE(ese->ele);
+ }
+ break;
+ }
+ }
+
+ if (bm->act_face) {
+ REMAP_FACE(bm->act_face);
+ }
+
+#undef MAP_VERT
+#undef MAP_EDGE
+#undef MAP_LOOP
+#undef MAP_EDGE
+
+#undef REMAP_VERT
+#undef REMAP_EDGE
+#undef REMAP_LOOP
+#undef REMAP_EDGE
+
+ /* Cleanup, re-use local tables if the current mesh had tables allocated.
+ * could use irrespective but it may use more memory then the caller wants (and not be needed). */
+ if (remap & BM_VERT) {
+ if (bm->vtable) {
+ SWAP(BMVert **, vtable_dst, bm->vtable);
+ bm->vtable_tot = bm->totvert;
+ bm->elem_table_dirty &= ~BM_VERT;
+ }
+ MEM_freeN(vtable_dst);
+ BLI_mempool_destroy(bm->vpool);
+ bm->vpool = vpool_dst;
+ }
+
+ if (remap & BM_EDGE) {
+ if (bm->etable) {
+ SWAP(BMEdge **, etable_dst, bm->etable);
+ bm->etable_tot = bm->totedge;
+ bm->elem_table_dirty &= ~BM_EDGE;
+ }
+ MEM_freeN(etable_dst);
+ BLI_mempool_destroy(bm->epool);
+ bm->epool = epool_dst;
+ }
+
+ if (remap & BM_LOOP) {
+ /* no loop table */
+ MEM_freeN(ltable_dst);
+ BLI_mempool_destroy(bm->lpool);
+ bm->lpool = lpool_dst;
+ }
+
+ if (remap & BM_FACE) {
+ if (bm->ftable) {
+ SWAP(BMFace **, ftable_dst, bm->ftable);
+ bm->ftable_tot = bm->totface;
+ bm->elem_table_dirty &= ~BM_FACE;
+ }
+ MEM_freeN(ftable_dst);
+ BLI_mempool_destroy(bm->fpool);
+ bm->fpool = fpool_dst;
+ }
+}
+
+/**
+ * Re-allocates mesh data with/without toolflags.
+ */
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
+{
+ if (bm->use_toolflags == use_toolflags) {
+ return;
+ }
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm);
+
+ BLI_mempool *vpool_dst = NULL;
+ BLI_mempool *epool_dst = NULL;
+ BLI_mempool *fpool_dst = NULL;
+
+ bm_mempool_init_ex(
+ &allocsize, use_toolflags,
+ &vpool_dst, &epool_dst, NULL, &fpool_dst);
+
+ if (use_toolflags == false) {
+ BLI_mempool_destroy(bm->vtoolflagpool);
+ BLI_mempool_destroy(bm->etoolflagpool);
+ BLI_mempool_destroy(bm->ftoolflagpool);
+
+ bm->vtoolflagpool = NULL;
+ bm->etoolflagpool = NULL;
+ bm->ftoolflagpool = NULL;
+ }
+
+ BM_mesh_rebuild(
+ bm,
+ &((struct BMeshCreateParams){.use_toolflags = use_toolflags,}),
+ vpool_dst, epool_dst, NULL, fpool_dst);
+
+ bm->use_toolflags = use_toolflags;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index b9cdc4ccf66..6a9540c3b60 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -32,7 +32,14 @@ struct MLoopNorSpaceArray;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
-BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize);
+
+struct BMeshCreateParams {
+ unsigned int use_toolflags : 1;
+};
+
+BMesh *BM_mesh_create(
+ const struct BMAllocTemplate *allocsize,
+ const struct BMeshCreateParams *params);
void BM_mesh_free(BMesh *bm);
void BM_mesh_data_free(BMesh *bm);
@@ -53,6 +60,8 @@ void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func,
const char *msg_a, const char *msg_b);
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
+
#ifndef NDEBUG
bool BM_mesh_elem_table_check(BMesh *bm);
#endif
@@ -83,6 +92,10 @@ void BM_mesh_remap(
const unsigned int *edge_idx,
const unsigned int *face_idx);
+void BM_mesh_rebuild(
+ BMesh *bm, const struct BMeshCreateParams *params,
+ struct BLI_mempool *vpool, struct BLI_mempool *epool, struct BLI_mempool *lpool, struct BLI_mempool *fpool);
+
typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
@@ -113,10 +126,4 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__)
-
-
-enum {
- BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0)
-};
-
#endif /* __BMESH_MESH_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index cf93fe0935e..30cd1df9c4e 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -75,15 +75,74 @@ extern "C" {
struct GHashIterator;
-#define BMO_elem_flag_test( bm, ele, oflag) _bmo_elem_flag_test (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_test_bool(bm, ele, oflag) _bmo_elem_flag_test_bool(bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_enable( bm, ele, oflag) _bmo_elem_flag_enable (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_disable( bm, ele, oflag) _bmo_elem_flag_disable (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_set( bm, ele, oflag, val) _bmo_elem_flag_set (bm, (ele)->oflags, oflag, val)
-#define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag)
-
-BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag);
+BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head)
+{
+ switch (ele_head->htype) {
+ case BM_VERT: return ((BMVert_OFlag *)ele_head)->oflags;
+ case BM_EDGE: return ((BMEdge_OFlag *)ele_head)->oflags;
+ default: return ((BMFace_OFlag *)ele_head)->oflags;
+ }
+}
+
+#define BMO_elem_flag_test(bm, ele, oflag) \
+ _bmo_elem_flag_test(bm, BMO_elem_flag_from_header(&(ele)->head), oflag)
+#define BMO_elem_flag_test_bool(bm, ele, oflag) \
+ _bmo_elem_flag_test_bool(bm, BMO_elem_flag_from_header(&(ele)->head), oflag)
+#define BMO_elem_flag_enable(bm, ele, oflag) \
+ _bmo_elem_flag_enable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+#define BMO_elem_flag_disable(bm, ele, oflag) \
+ _bmo_elem_flag_disable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+#define BMO_elem_flag_set(bm, ele, oflag, val) \
+ _bmo_elem_flag_set(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag, val)
+#define BMO_elem_flag_toggle(bm, ele, oflag) \
+ _bmo_elem_flag_toggle(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+
+/* take care not to instansiate args multiple times */
+#ifdef __GNUC___
+#define _BMO_CAST_V_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_VERT(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_VERT), (const BMVert_OFlag *)_e); })
+#define _BMO_CAST_E_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_EDGE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_EDGE), (const BMEdge_OFlag *)_e); })
+#define _BMO_CAST_F_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_FACE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_FACE), (const BMFace_OFlag *)_e); })
+#define _BMO_CAST_V(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_VERT_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_VERT), (BMVert_OFlag *)_e); })
+#define _BMO_CAST_E(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_EDGE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_EDGE), (BMEdge_OFlag *)_e); })
+#define _BMO_CAST_F(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_FACE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_FACE), (BMFace_OFlag *)_e); })
+#else
+#define _BMO_CAST_V_CONST(e) (BM_CHECK_TYPE_VERT(e), (const BMVert_OFlag *)e)
+#define _BMO_CAST_E_CONST(e) (BM_CHECK_TYPE_EDGE(e), (const BMEdge_OFlag *)e)
+#define _BMO_CAST_F_CONST(e) (BM_CHECK_TYPE_FACE(e), (const BMFace_OFlag *)e)
+#define _BMO_CAST_V(e) (BM_CHECK_TYPE_VERT_NONCONST(e), (BMVert_OFlag *)e)
+#define _BMO_CAST_E(e) (BM_CHECK_TYPE_EDGE_NONCONST(e), (BMEdge_OFlag *)e)
+#define _BMO_CAST_F(e) (BM_CHECK_TYPE_FACE_NONCONST(e), (BMFace_OFlag *)e)
+#endif
+
+#define BMO_vert_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_V_CONST(e)->oflags, oflag)
+#define BMO_vert_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_V_CONST(e)->oflags, oflag)
+#define BMO_vert_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_V(e)->oflags, oflag)
+#define BMO_vert_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_V(e)->oflags, oflag)
+#define BMO_vert_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_V(e)->oflags, oflag, val)
+#define BMO_vert_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_V(e)->oflags, oflag)
+
+#define BMO_edge_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_E_CONST(e)->oflags, oflag)
+#define BMO_edge_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_E_CONST(e)->oflags, oflag)
+#define BMO_edge_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_E(e)->oflags, oflag)
+#define BMO_edge_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_E(e)->oflags, oflag)
+#define BMO_edge_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_E(e)->oflags, oflag, val)
+#define BMO_edge_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_E(e)->oflags, oflag)
+
+#define BMO_face_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_F_CONST(e)->oflags, oflag)
+#define BMO_face_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_F_CONST(e)->oflags, oflag)
+#define BMO_face_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_F(e)->oflags, oflag)
+#define BMO_face_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_F(e)->oflags, oflag)
+#define BMO_face_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_F(e)->oflags, oflag, val)
+#define BMO_face_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_F(e)->oflags, oflag)
+
+BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, const BMFlagLayer *oflags, const short oflag);
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
index 00fcd9e7a9b..eb1c161f19d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
@@ -39,32 +39,37 @@
/* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
-BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag)
+BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
return oflags[bm->toolflag_index].f & oflag;
}
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag)
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
return (oflags[bm->toolflag_index].f & oflag) != 0;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f |= oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f &= (short)~oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val)
{
+ BLI_assert(bm->use_toolflags);
if (val) oflags[bm->toolflag_index].f |= oflag;
else oflags[bm->toolflag_index].f &= (short)~oflag;
}
@@ -72,6 +77,7 @@ BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short o
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f ^= oflag;
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 960ff568e93..706a7f74ed2 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -548,27 +548,44 @@ static int bmo_mesh_flag_count(
BMesh *bm, const char htype, const short oflag,
const bool test_for_enabled)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
+ int count_vert = 0, count_edge = 0, count_face = 0;
- const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
-
- BMIter iter;
- int count = 0;
- BMElemF *ele_f;
- int i;
-
- for (i = 0; i < 3; i++) {
- if (htype & flag_types[i]) {
- BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) {
- if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
- count++;
+#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \
+ (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0))
+ {
+#pragma omp section
+ if (htype & BM_VERT) {
+ BMIter iter;
+ BMVert *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_vert++;
+ }
+ }
+ }
+#pragma omp section
+ if (htype & BM_EDGE) {
+ BMIter iter;
+ BMEdge *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_edge++;
+ }
+ }
+ }
+#pragma omp section
+ if (htype & BM_FACE) {
+ BMIter iter;
+ BMFace *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
+ if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_face++;
+ }
}
}
}
- return count;
+ return (count_vert + count_edge + count_face);
}
@@ -584,21 +601,32 @@ int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
-
- const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
- BMElemF *ele;
- int i;
-
-#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
- for (i = 0; i < 3; i++) {
- if (htype & flag_types[i]) {
+#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \
+ (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0))
+ {
+#pragma omp section
+ if (htype & BM_VERT) {
BMIter iter;
- BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
- BMO_elem_flag_disable(bm, ele, oflag);
+ BMVert *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BMO_vert_flag_disable(bm, ele, oflag);
+ }
+ }
+#pragma omp section
+ if (htype & BM_EDGE) {
+ BMIter iter;
+ BMEdge *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BMO_edge_flag_disable(bm, ele, oflag);
+ }
+ }
+#pragma omp section
+ if (htype & BM_FACE) {
+ BMIter iter;
+ BMFace *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
+ BMO_face_flag_disable(bm, ele, oflag);
}
}
}
@@ -1007,7 +1035,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_VERT) {
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1016,7 +1044,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_EDGE) {
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1025,7 +1053,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_FACE) {
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1213,7 +1241,7 @@ static void bmo_flag_layer_alloc(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BLI_mempool *newpool = bm->vtoolflagpool;
@@ -1223,14 +1251,14 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BLI_mempool *newpool = bm->etoolflagpool;
@@ -1239,14 +1267,14 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BLI_mempool *newpool = bm->ftoolflagpool;
@@ -1255,7 +1283,7 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
@@ -1292,7 +1320,7 @@ static void bmo_flag_layer_free(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BLI_mempool *newpool = bm->vtoolflagpool;
@@ -1302,14 +1330,14 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BLI_mempool *newpool = bm->etoolflagpool;
@@ -1318,14 +1346,14 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BLI_mempool *newpool = bm->ftoolflagpool;
@@ -1334,7 +1362,7 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
@@ -1361,31 +1389,31 @@ static void bmo_flag_layer_clear(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index fff6bea044c..13b6a3c13c5 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -371,7 +371,7 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
}
/**
- * Compute the tanget of the face, using the longest edge.
+ * Compute the tangent of the face, using the longest edge.
*/
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
{
@@ -384,7 +384,7 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
}
/**
- * Compute the tanget of the face, using the two longest disconected edges.
+ * Compute the tangent of the face, using the two longest disconnected edges.
*
* \param r_tangent: Calculated unit length tangent (return value).
*/
@@ -449,7 +449,7 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
}
/**
- * Compute the tanget of the face, using the edge farthest away from any vertex in the face.
+ * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
*
* \param r_tangent: Calculated unit length tangent (return value).
*/
@@ -485,7 +485,7 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
}
/**
- * Compute the tanget of the face, using longest distance between vertices on the face.
+ * Compute the tangent of the face, using longest distance between vertices on the face.
*
* \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
*/
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 018700c0efa..279440984bb 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -49,7 +49,7 @@ static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) {
+ else if (walker->mask_vert && !BMO_vert_flag_test(walker->bm, v, walker->mask_vert)) {
return false;
}
else {
@@ -62,7 +62,7 @@ static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) {
+ else if (walker->mask_edge && !BMO_edge_flag_test(walker->bm, e, walker->mask_edge)) {
return false;
}
else {
@@ -75,7 +75,7 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) {
+ else if (walker->mask_face && !BMO_face_flag_test(walker->bm, f, walker->mask_face)) {
return false;
}
else {
@@ -223,7 +223,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
do {
if (!BLI_gset_haskey(walker->visit_set, curedge)) {
if (!walker->restrictflag ||
- (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag)))
+ (walker->restrictflag && BMO_edge_flag_test(walker->bm, curedge, walker->restrictflag)))
{
BMwShellWalker *newstate;
@@ -748,7 +748,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
iwalk = BMW_state_add(walker);
iwalk->base = owalk.base;
- //if (!BMO_elem_flag_test(walker->bm, l->f, walker->restrictflag))
+ //if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag))
// iwalk->curloop = l->radial_next;
iwalk->curloop = l; //else iwalk->curloop = l;
iwalk->lastv = v;
diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c
index 4a292c33472..c68d92ea5e0 100644
--- a/source/blender/bmesh/operators/bmo_beautify.c
+++ b/source/blender/bmesh/operators/bmo_beautify.c
@@ -52,7 +52,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op)
int edge_array_len = 0;
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -68,8 +68,8 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op)
/* edge is manifold and can be rotated */
if (BM_edge_rotate_check(e) &&
/* faces are tagged */
- BMO_elem_flag_test(bm, e->l->f, FACE_MARK) &&
- BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK))
+ BMO_face_flag_test(bm, e->l->f, FACE_MARK) &&
+ BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK))
{
edge_array[edge_array_len] = e;
edge_array_len++;
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index a0149a41921..6ef0fd6b084 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -131,13 +131,13 @@ static void bm_face_edges_tag_out(BMesh *bm, BMFace *f)
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT);
} while ((l_iter = l_iter->next) != l_first);
}
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
- return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK);
+ return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK);
}
static void bridge_loop_pair(
@@ -425,7 +425,7 @@ static void bridge_loop_pair(
if (f_example && (f_example != f)) {
BM_elem_attrs_copy(bm, bm, f_example, f);
}
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
BM_elem_flag_enable(f, BM_ELEM_TAG);
/* tag all edges of the face, untag the loop edges after */
@@ -486,7 +486,7 @@ static void bridge_loop_pair(
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
@@ -498,7 +498,7 @@ static void bridge_loop_pair(
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
@@ -520,7 +520,7 @@ static void bridge_loop_pair(
if (el_next) {
if (el->data != el_next->data) {
BMEdge *e = BM_edge_exists(el->data, el_next->data);
- BMO_elem_flag_disable(bm, e, EDGE_OUT);
+ BMO_edge_flag_disable(bm, e, EDGE_OUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
index 0213329118c..5c9cd8dc3fa 100644
--- a/source/blender/bmesh/operators/bmo_connect.c
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -62,10 +62,10 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) &&
+ if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) &&
/* ensure this vertex isnt part of a contiguous group */
- ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
- (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0)))
+ ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
+ (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0)))
{
if (!l_tag_prev) {
l_tag_prev = l_tag_first = l_iter;
@@ -75,7 +75,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) {
BMEdge *e;
e = BM_edge_exists(l_tag_prev->v, l_iter->v);
- if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) {
+ if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) {
BMLoop **l_pair = STACK_PUSH_RET(loops_split);
l_pair[0] = l_tag_prev;
l_pair[1] = l_iter;
@@ -138,8 +138,8 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
if (!l_new || !f_new) {
return -1;
}
- // BMO_elem_flag_enable(bm, f_new, FACE_NEW);
- BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT);
+ // BMO_face_flag_enable(bm, f_new, FACE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT);
}
return 1;
@@ -164,12 +164,12 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
BMIter iter;
BMLoop *l_iter;
- BMO_elem_flag_enable(bm, v, VERT_INPUT);
+ BMO_vert_flag_enable(bm, v, VERT_INPUT);
BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) {
f = l_iter->f;
- if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) {
- if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
- BMO_elem_flag_enable(bm, f, FACE_TAG);
+ if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) {
+ if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
+ BMO_face_flag_enable(bm, f, FACE_TAG);
if (f->len > 3) {
BLI_LINKSTACK_PUSH(faces, f);
}
@@ -179,11 +179,11 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
/* flag edges even if these are not newly created
* this way cut-pairs that include co-linear edges will get
* predictable output. */
- if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) {
- BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ);
+ if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) {
+ BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ);
}
- if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) {
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ);
+ if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) {
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
index 8b9c60ada52..9bb67ed9341 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -107,10 +107,10 @@ static bool bm_face_split_by_concave(
int i;
for (i = 0; i < faces_array_tot; i++) {
BMFace *f = faces_array[i];
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
}
}
- BMO_elem_flag_enable(bm, f_base, FACE_OUT);
+ BMO_face_flag_enable(bm, f_base, FACE_OUT);
if (edges_array_tot) {
int i;
@@ -120,7 +120,7 @@ static bool bm_face_split_by_concave(
for (i = 0; i < edges_array_tot; i++) {
BMLoop *l_pair[2];
BMEdge *e = edges_array[i];
- BMO_elem_flag_enable(bm, e, EDGE_OUT);
+ BMO_edge_flag_enable(bm, e, EDGE_OUT);
if (BM_edge_is_contiguous(e) &&
BM_edge_loop_pair(e, &l_pair[0], &l_pair[1]))
@@ -153,7 +153,7 @@ static bool bm_face_split_by_concave(
BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f};
f_new = BM_faces_join(bm, f_pair, 2, true);
if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index c80fb95c44a..9b3e1d38feb 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -136,9 +136,9 @@ static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], co
r_f_pair[0] = f;
r_f_pair[1] = f_new;
- BMO_elem_flag_enable(bm, f, FACE_OUT);
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
- BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
+ BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT);
return true;
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 3b860778e1c..3eb6fe0cb97 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -67,18 +67,29 @@
#define ELE_TOUCHED 4
#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \
- BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
+ BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \
- BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
+ BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
+#if 0
#define ELE_TOUCH_TEST(e) \
(CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \
BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED))
+#endif
#define ELE_TOUCH_MARK(e) \
{ CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \
BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0)
+#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+
+// #define ELE_TOUCH_TEST_EDGE(v) BMO_edge_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_EDGE(v) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+
+// #define ELE_TOUCH_TEST_FACE(v) BMO_face_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_FACE(v) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+
// #define DEBUG_PRINT
typedef struct PathContext {
@@ -352,7 +363,7 @@ static PathLinkState *state_step__face_edges(
BMElem *ele_next_from = (BMElem *)l_iter->f;
if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
- (ELE_TOUCH_TEST(ele_next) == false))
+ (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false))
{
min_dist_dir_update(mddir, dist_dir);
mddir->dist_min[index] = dist_test;
@@ -397,7 +408,7 @@ static PathLinkState *state_step__face_verts(
BMElem *ele_next_from = (BMElem *)l_iter->f;
if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
- (ELE_TOUCH_TEST(ele_next) == false))
+ (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false))
{
min_dist_dir_update(mddir, dist_dir);
mddir->dist_min[index] = dist_test;
@@ -480,7 +491,7 @@ static bool state_step(PathContext *pc, PathLinkState *state)
if (state_isect_co_exact(pc, v_other->co)) {
BMElem *ele_next = (BMElem *)v_other;
BMElem *ele_next_from = (BMElem *)e;
- if (ELE_TOUCH_TEST(ele_next) == false) {
+ if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) {
state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from);
}
}
@@ -703,11 +714,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
BMVert *v_new;
float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co);
v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
- BMO_elem_flag_enable(bm, v_new, VERT_OUT);
+ BMO_vert_flag_enable(bm, v_new, VERT_OUT);
}
else if (link->ele->head.htype == BM_VERT) {
BMVert *v = (BMVert *)link->ele;
- BMO_elem_flag_enable(bm, v, VERT_OUT);
+ BMO_vert_flag_enable(bm, v, VERT_OUT);
}
else {
BLI_assert(0);
@@ -715,8 +726,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
} while ((link = link->next));
}
- BMO_elem_flag_enable(bm, pc.v_a, VERT_OUT);
- BMO_elem_flag_enable(bm, pc.v_b, VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT);
BLI_mempool_destroy(pc.link_pool);
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index a1e20dab63e..7b8cb36ab59 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -52,12 +52,19 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
/* count number of each element type we were passe */
BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) {
switch (h->htype) {
- case BM_VERT: totv++; break;
- case BM_EDGE: tote++; break;
- case BM_FACE: totf++; break;
+ case BM_VERT:
+ BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW);
+ totv++;
+ break;
+ case BM_EDGE:
+ BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW);
+ tote++;
+ break;
+ case BM_FACE:
+ BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW);
+ totf++;
+ break;
}
-
- BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW);
}
/* --- Support Edge Creation ---
@@ -71,7 +78,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
/* create edge */
e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_OUT);
+ BMO_edge_flag_enable(bm, e, ELE_OUT);
tote += 1;
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
return;
@@ -131,10 +138,10 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMEdge *e;
e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
tote += 2;
}
}
@@ -236,7 +243,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
for (ese = bm->selected.first; ese; ese = ese->next) {
if (ese->htype == BM_VERT) {
- if (BMO_elem_flag_test(bm, (BMElemF *)ese->ele, ELE_NEW)) {
+ if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) {
tot_ese_v++;
}
else {
@@ -256,7 +263,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMVert *v = (BMVert *)ese->ele;
if (v_prev) {
BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_OUT);
+ BMO_edge_flag_enable(bm, e, ELE_OUT);
}
v_prev = v;
}
@@ -286,7 +293,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE);
if (f) {
- BMO_elem_flag_enable(bm, f, ELE_OUT);
+ BMO_face_flag_enable(bm, f, ELE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 86062ff0b66..05efb14a699 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -74,10 +74,10 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f)
for (f2 = BMW_begin(&regwalker, f); f2; f2 = BMW_step(&regwalker)) {
BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) {
l3 = l2->radial_next;
- if (BMO_elem_flag_test(bm, l3->f, FACE_MARK) !=
- BMO_elem_flag_test(bm, l2->f, FACE_MARK))
+ if (BMO_face_flag_test(bm, l3->f, FACE_MARK) !=
+ BMO_face_flag_test(bm, l2->f, FACE_MARK))
{
- if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) {
return false;
}
}
@@ -99,14 +99,14 @@ static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
}
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag)) {
+ if (BMO_vert_flag_test(bm, v, oflag)) {
if (BM_vert_is_edge_pair(v) == false) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
if (l->f->len > 3) {
- if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 &&
- BMO_elem_flag_test(bm, l->prev->v, oflag) == 0)
+ if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 &&
+ BMO_vert_flag_test(bm, l->prev->v, oflag) == 0)
{
BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true);
}
@@ -153,7 +153,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BMVert *v;
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
+ BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
@@ -162,7 +162,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
/* collect region */
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
BMFace *f_iter;
- if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
+ if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
continue;
}
@@ -181,8 +181,8 @@ 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_TAG);
- BMO_elem_flag_enable(bm, f_iter, FACE_ORIG);
+ BMO_face_flag_disable(bm, f_iter, FACE_TAG);
+ BMO_face_flag_enable(bm, f_iter, FACE_ORIG);
}
if (BMO_error_occurred(bm)) {
@@ -229,8 +229,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
/* if making the new face failed (e.g. overlapping test)
* 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_face_flag_disable(bm, f_new, FACE_ORIG);
+ BMO_face_flag_enable(bm, f_new, FACE_NEW);
}
/* Typically no faces need to be deleted */
@@ -243,7 +243,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BMVert *v, *v_next;
BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
if (BM_vert_is_edge_pair(v)) {
BM_vert_collapse_edge(bm, v->e, v, true, true);
}
@@ -285,14 +285,14 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMIter itersub;
int untag_count = 0;
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EDGE_TAG)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) {
untag_count++;
}
}
/* check that we have 2 edges remaining after dissolve */
if (untag_count <= 2) {
- BMO_elem_flag_enable(bm, v, VERT_TAG);
+ BMO_vert_flag_enable(bm, v, VERT_TAG);
}
}
@@ -301,7 +301,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
+ BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
@@ -314,8 +314,8 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMLoop *l_first, *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
do {
- BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC);
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC);
+ BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -341,12 +341,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
/* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
* so do this in a separate pass instead. */
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) {
+ if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
BM_edge_kill(bm, e);
}
}
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) {
+ if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
BM_vert_kill(bm, v);
}
}
@@ -355,7 +355,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
if (BM_vert_is_edge_pair(v)) {
BM_vert_collapse_edge(bm, v->e, v, true, true);
}
@@ -376,7 +376,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear");
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
- BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC);
+ BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC);
}
if (use_face_split) {
@@ -388,7 +388,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
if (!BM_vert_is_edge_pair(v)) {
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR);
+ BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR);
break;
}
}
@@ -406,8 +406,8 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC);
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC);
+ BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
} while ((l_iter = l_iter->next) != l_first);
e_first = l_first->e;
@@ -428,14 +428,14 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
/* tag here so we avoid feedback loop (checking topology as we edit) */
if (BM_vert_is_edge_pair(v)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK_PAIR);
+ BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR);
}
}
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
BMIter itersub;
- if (!BMO_elem_flag_test(bm, v, VERT_MARK_PAIR)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) {
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
BMFace *fa, *fb;
if (BM_edge_face_pair(e, &fa, &fb)) {
@@ -456,7 +456,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
* so do this in a separate pass instead. */
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) {
+ if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
BM_edge_kill(bm, e);
}
}
@@ -469,7 +469,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
}
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) {
+ if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
BM_vert_kill(bm, v);
}
}
@@ -518,9 +518,9 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* collapse zero length edges, this accounts for zero area faces too */
found = false;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (BM_edge_calc_length_squared(e) < dist_sq) {
- BMO_elem_flag_enable(bm, e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE);
found = true;
}
}
@@ -543,7 +543,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* clip degenerate ears from the face */
found = false;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (e->l && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
@@ -553,11 +553,11 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
/* check we're marked to tested (radial edge already tested) */
- BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
+ BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
/* check edges are not already going to be collapsed */
- !BMO_elem_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
- !BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE)))
+ !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
+ !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE)))
{
/* test if the faces loop (ear) is degenerate */
float dir_prev[3], len_prev;
@@ -577,14 +577,14 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* both edges the same length */
if (l_iter->f->len == 3) {
/* ideally this would have been discovered with short edge test above */
- BMO_elem_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE);
found = true;
}
else {
/* add a joining edge and tag for removal */
BMLoop *l_split;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
reset = true;
}
@@ -599,7 +599,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
BLI_assert(v_new == l_iter->next->v);
(void)v_new;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
}
reset = true;
@@ -613,7 +613,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
BLI_assert(v_new == l_iter->prev->v);
(void)v_new;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
}
reset = true;
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index fd430de80f9..56639a097b6 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -63,7 +63,7 @@ static BMVert *bmo_vert_copy(
BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst);
/* Mark the vert for output */
- BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW);
+ BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);
return v_dst;
}
@@ -94,7 +94,7 @@ static BMEdge *bmo_edge_copy(
BMLoop *l_iter_src, *l_first_src;
l_iter_src = l_first_src = e_src->l;
do {
- if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
rlen++;
}
} while ((l_iter_src = l_iter_src->radial_next) != l_first_src);
@@ -123,7 +123,7 @@ static BMEdge *bmo_edge_copy(
BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst);
/* Mark the edge for output */
- BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW);
+ BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW);
return e_dst;
}
@@ -175,7 +175,7 @@ static BMFace *bmo_face_copy(
(l_iter_src = l_iter_src->next) != l_first_src);
/* Mark the face for output */
- BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW);
+ BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW);
return f_dst;
}
@@ -209,8 +209,8 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
/* duplicate flagged vertices */
BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, v, DUPE_INPUT) &&
- !BMO_elem_flag_test(bm_src, v, DUPE_DONE))
+ if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) &&
+ BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false)
{
BMIter iter;
bool isolated = true;
@@ -218,7 +218,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
isolated = false;
break;
}
@@ -226,7 +226,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
if (isolated) {
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT)) {
+ if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) {
isolated = false;
break;
}
@@ -237,53 +237,53 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2);
}
- BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
}
}
/* now we dupe all the edges */
BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT) &&
- !BMO_elem_flag_test(bm_src, e, DUPE_DONE))
+ if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) &&
+ BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false)
{
/* make sure that verts are copied */
- if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash);
- BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE);
}
- if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash);
- BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE);
}
/* now copy the actual edge */
bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
bm_dst, bm_src, e, vhash, ehash);
- BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
+ BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
}
}
/* first we dupe all flagged faces and their elements from source */
BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
/* vertex pass */
BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
- if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
- BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
}
}
/* edge pass */
BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
- if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) {
+ if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) {
bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
bm_dst, bm_src, e, vhash, ehash);
- BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
+ BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
}
}
bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash);
- BMO_elem_flag_enable(bm_src, f, DUPE_DONE);
+ BMO_face_flag_enable(bm_src, f, DUPE_DONE);
}
}
@@ -408,26 +408,26 @@ void bmo_split_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
bool found = false;
BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) {
found = true;
break;
}
}
if (found == false) {
- BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
+ BMO_edge_flag_enable(bm, e, SPLIT_INPUT);
}
}
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
bool found = false;
BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) {
found = true;
break;
}
}
if (found == false) {
- BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
+ BMO_vert_flag_enable(bm, v, SPLIT_INPUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index f348014cead..64b092da5c8 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -94,8 +94,8 @@ static BMEdge *edge_next(BMesh *bm, BMEdge *e)
for (i = 0; i < 2; i++) {
BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) {
- if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) &&
- (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) &&
+ if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) &&
+ (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) &&
(e2 != e))
{
return e2;
@@ -144,7 +144,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
count = 0;
while (1) {
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
- if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) {
if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 ||
BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1)
{
@@ -169,7 +169,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
i = 0;
while (e) {
- BMO_elem_flag_enable(bm, e, EDGE_VIS);
+ BMO_edge_flag_enable(bm, e, EDGE_VIS);
BLI_array_grow_one(edges);
edges[i] = e;
@@ -258,9 +258,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
}
e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
}
else if (edges1) {
BMVert *v1, *v2;
@@ -270,7 +270,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
i = BLI_array_count(edges1) - 1;
v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
}
}
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 5a3bef6ba81..87369472df7 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -70,10 +70,10 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
BMLoop *l_org, *l_org_first;
BMLoop *l_new;
- BMO_elem_flag_enable(bm, f_org, EXT_DEL);
+ BMO_face_flag_enable(bm, f_org, EXT_DEL);
f_new = BM_face_copy(bm, bm, f_org, true, true);
- BMO_elem_flag_enable(bm, f_new, EXT_KEEP);
+ BMO_face_flag_enable(bm, f_new, EXT_KEEP);
if (select_history_map) {
BMEditSelection *ese;
@@ -188,9 +188,9 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
BMEdge *e, *e_new;
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
- BMO_elem_flag_enable(bm, e, EXT_INPUT);
- BMO_elem_flag_enable(bm, e->v1, EXT_INPUT);
- BMO_elem_flag_enable(bm, e->v2, EXT_INPUT);
+ BMO_edge_flag_enable(bm, e, EXT_INPUT);
+ BMO_vert_flag_enable(bm, e->v1, EXT_INPUT);
+ BMO_vert_flag_enable(bm, e->v2, EXT_INPUT);
}
BMO_op_initf(
@@ -228,13 +228,14 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
bm_extrude_copy_face_loop_attributes(bm, f);
- if (BMO_elem_flag_test(bm, e, EXT_INPUT))
+ if (BMO_edge_flag_test(bm, e, EXT_INPUT)) {
e = e_new;
+ }
- BMO_elem_flag_enable(bm, f, EXT_KEEP);
- BMO_elem_flag_enable(bm, e, EXT_KEEP);
- BMO_elem_flag_enable(bm, e->v1, EXT_KEEP);
- BMO_elem_flag_enable(bm, e->v2, EXT_KEEP);
+ BMO_face_flag_enable(bm, f, EXT_KEEP);
+ BMO_edge_flag_enable(bm, e, EXT_KEEP);
+ BMO_vert_flag_enable(bm, e->v1, EXT_KEEP);
+ BMO_vert_flag_enable(bm, e->v2, EXT_KEEP);
}
@@ -258,7 +259,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, dupev, EXT_KEEP);
+ BMO_vert_flag_enable(bm, dupev, EXT_KEEP);
if (has_vskin)
bm_extrude_disable_skin_root(bm, v);
@@ -279,7 +280,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
}
e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, e, EXT_KEEP);
+ BMO_edge_flag_enable(bm, e, EXT_KEEP);
}
if (select_history_map) {
@@ -350,7 +351,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
int edge_face_tot;
- if (!BMO_elem_flag_test(bm, e, EXT_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) {
continue;
}
@@ -358,7 +359,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
edge_face_tot = 0; /* edge/face count */
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
found = true;
delorig = true;
break;
@@ -369,7 +370,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
if ((edge_face_tot > 1) && (found == false)) {
/* edge has a face user, that face isn't extrude input */
- BMO_elem_flag_enable(bm, e, EXT_DEL);
+ BMO_edge_flag_enable(bm, e, EXT_DEL);
}
}
}
@@ -380,7 +381,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
found = false;
BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) {
+ if (!BMO_edge_flag_test(bm, e, EXT_INPUT) ||
+ !BMO_edge_flag_test(bm, e, EXT_DEL))
+ {
found = true;
break;
}
@@ -389,7 +392,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
/* avoid an extra loop */
if (found == true) {
BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
found = true;
break;
}
@@ -397,14 +400,14 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
if (found == false) {
- BMO_elem_flag_enable(bm, v, EXT_DEL);
+ BMO_vert_flag_enable(bm, v, EXT_DEL);
}
}
}
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, EXT_INPUT)) {
- BMO_elem_flag_enable(bm, f, EXT_DEL);
+ if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
+ BMO_face_flag_enable(bm, f, EXT_DEL);
}
}
@@ -426,7 +429,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out");
- if (bm->act_face && BMO_elem_flag_test(bm, bm->act_face, EXT_INPUT)) {
+ if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) {
bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face);
}
@@ -437,7 +440,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
/* if not delorig, reverse loops of original face */
if (!delorig) {
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
BM_face_normal_flip(bm, f);
}
}
@@ -583,7 +586,7 @@ static void calc_solidify_normals(BMesh *bm)
BM_mesh_elem_index_ensure(bm, BM_EDGE);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (!BMO_face_flag_test(bm, f, FACE_MARK)) {
continue;
}
@@ -591,15 +594,15 @@ static void calc_solidify_normals(BMesh *bm)
/* And mark all edges and vertices on the
* marked faces */
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
- BMO_elem_flag_enable(bm, e->v1, VERT_MARK);
- BMO_elem_flag_enable(bm, e->v2, VERT_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
+ BMO_vert_flag_enable(bm, e->v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, e->v2, VERT_MARK);
edge_face_count[BM_elem_index_get(e)]++;
}
}
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
continue;
}
@@ -608,9 +611,9 @@ static void calc_solidify_normals(BMesh *bm)
if (i == 0 || i > 2) {
/* Edge & vertices are non-manifold even when considering
* only marked faces */
- BMO_elem_flag_enable(bm, e, EDGE_NONMAN);
- BMO_elem_flag_enable(bm, e->v1, VERT_NONMAN);
- BMO_elem_flag_enable(bm, e->v2, VERT_NONMAN);
+ BMO_edge_flag_enable(bm, e, EDGE_NONMAN);
+ BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN);
+ BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN);
}
}
MEM_freeN(edge_face_count);
@@ -618,11 +621,11 @@ static void calc_solidify_normals(BMesh *bm)
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
if (!BM_vert_is_manifold(v)) {
- BMO_elem_flag_enable(bm, v, VERT_NONMAN);
+ BMO_vert_flag_enable(bm, v, VERT_NONMAN);
continue;
}
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
zero_v3(v->no);
}
}
@@ -631,20 +634,20 @@ static void calc_solidify_normals(BMesh *bm)
/* If the edge is not part of a the solidify region
* its normal should not be considered */
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
continue;
}
/* If the edge joins more than two marked faces high
* quality normal computation won't work */
- if (BMO_elem_flag_test(bm, e, EDGE_NONMAN)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) {
continue;
}
f1 = f2 = NULL;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
if (f1 == NULL) {
f1 = f;
}
@@ -664,8 +667,7 @@ static void calc_solidify_normals(BMesh *bm)
/* two faces using this edge, calculate the edge normal
* using the angle between the faces as a weighting */
add_v3_v3v3(edge_normal, f1->no, f2->no);
- normalize_v3(edge_normal);
- mul_v3_fl(edge_normal, angle);
+ normalize_v3_length(edge_normal, angle);
}
else {
/* can't do anything useful here!
@@ -689,11 +691,11 @@ static void calc_solidify_normals(BMesh *bm)
/* normalize accumulated vertex normal */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK)) {
continue;
}
- if (BMO_elem_flag_test(bm, v, VERT_NONMAN)) {
+ if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) {
/* use standard normals for vertices connected to non-manifold edges */
BM_vert_normal_update(v);
}
@@ -701,7 +703,7 @@ static void calc_solidify_normals(BMesh *bm)
/* exceptional case, totally flat. use the normal
* of any marked face around the vertex */
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
break;
}
}
@@ -726,7 +728,7 @@ static void solidify_add_thickness(BMesh *bm, const float dist)
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
/* array for passing verts to angle_poly_v3 */
float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index 0fbaf5ff11a..c68130bc11d 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -59,14 +59,14 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
i = 0;
BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
BMIter viter;
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
- if (BMO_elem_flag_test(bm, v, VERT_USED) == false) {
+ if (BMO_vert_flag_test(bm, v, VERT_USED) == false) {
if (i == tote) {
goto cleanup;
}
- BMO_elem_flag_enable(bm, v, VERT_USED);
+ BMO_vert_flag_enable(bm, v, VERT_USED);
verts[i++] = v;
}
}
@@ -103,21 +103,21 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
while (totv_used < totv) {
for (i = 0; i < totv; i++) {
v = verts[i];
- if (BMO_elem_flag_test(bm, v, VERT_USED)) {
+ if (BMO_vert_flag_test(bm, v, VERT_USED)) {
break;
}
}
/* this should never fail, as long as (totv_used < totv)
* we should have marked verts available */
- BLI_assert(BMO_elem_flag_test(bm, v, VERT_USED));
+ BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED));
/* watch it, 'i' is used for final face length */
i = 0;
do {
/* we know that there are 2 edges per vertex so no need to check */
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (e != e_prev) {
e_next = e;
break;
@@ -127,7 +127,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
/* fill in the array */
f_verts[i] = v;
- BMO_elem_flag_disable(bm, v, VERT_USED);
+ BMO_vert_flag_disable(bm, v, VERT_USED);
totv_used++;
/* step over the edges */
@@ -141,7 +141,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
/* don't use calc_edges option because we already have the edges */
f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false);
- BMO_elem_flag_enable(bm, f, ELE_OUT);
+ BMO_face_flag_enable(bm, f, ELE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 77556591728..04ae915b707 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -466,7 +466,7 @@ static void bm_grid_fill_array(
/* end interp */
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
@@ -585,7 +585,7 @@ static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, boo
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
- return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
+ return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
}
static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v))
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 2dfad5a1f47..9c41e4f2115 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -81,7 +81,7 @@ static void hull_add_triangle(
/* Mark triangles vertices as not interior */
for (i = 0; i < 3; i++)
- BMO_elem_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE);
+ BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE);
BLI_gset_insert(hull_triangles, t);
normal_tri_v3(t->no, v1->co, v2->co, v3->co);
@@ -93,8 +93,8 @@ static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e)
BMFace *f;
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT) ||
- !BMO_elem_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM))
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) ||
+ BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false)
{
return f;
}
@@ -124,9 +124,9 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
* disabled, but an output face in the hull is the
* same as a face in the existing mesh, it should not
* be marked as unused or interior. */
- BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
- BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE);
- BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
}
else {
/* Look for an adjacent face that existed before the hull */
@@ -140,12 +140,12 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
BM_face_copy_shared(bm, f, NULL, NULL);
}
/* Mark face for 'geom.out' slot and select */
- BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
BM_face_select_set(bm, f, true);
/* Mark edges for 'geom.out' slot */
for (i = 0; i < 3; i++) {
- BMO_elem_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM);
+ BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM);
}
}
else {
@@ -154,17 +154,17 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
const int next = (i == 2 ? 0 : i + 1);
BMEdge *e = BM_edge_exists(t->v[i], t->v[next]);
if (e &&
- BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) &&
- !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE))
+ BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) &&
+ !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE))
{
- BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
}
}
}
/* Mark verts for 'geom.out' slot */
for (i = 0; i < 3; i++) {
- BMO_elem_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM);
+ BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM);
}
}
}
@@ -292,8 +292,8 @@ static void hull_remove_overlapping(
BM_vert_in_face(t->v[2], f) && f_on_hull)
{
t->skip = true;
- BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
- BMO_elem_flag_enable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE);
}
}
}
@@ -310,13 +310,13 @@ static void hull_mark_interior_elements(
/* Check for interior edges too */
BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
if (!hull_final_edges_lookup(final_edges, e->v1, e->v2))
- BMO_elem_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE);
}
/* Mark all input faces as interior, some may be unmarked in
* hull_remove_overlapping() */
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- BMO_elem_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE);
}
}
@@ -333,47 +333,50 @@ static void hull_tag_unused(BMesh *bm, BMOperator *op)
* the hull), but that aren't also used by elements outside the
* input set */
BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
- if (BMO_elem_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) {
+ if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) {
bool del = true;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
- if (del)
- BMO_elem_flag_enable(bm, v, HULL_FLAG_DEL);
+ if (del) {
+ BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL);
+ }
}
}
BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
- if (BMO_elem_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) {
+ if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) {
bool del = true;
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
- if (del)
- BMO_elem_flag_enable(bm, e, HULL_FLAG_DEL);
+ if (del) {
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL);
+ }
}
}
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE))
- BMO_elem_flag_enable(bm, f, HULL_FLAG_DEL);
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) {
+ BMO_face_flag_enable(bm, f, HULL_FLAG_DEL);
+ }
}
}
@@ -387,10 +390,10 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op)
/* Unmark any hole faces if they are isolated or part of a
* border */
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) {
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
if (BM_edge_is_boundary(e)) {
- BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
break;
}
}
@@ -405,14 +408,14 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op)
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
any_faces = true;
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
hole = false;
break;
}
}
if (hole && any_faces)
- BMO_elem_flag_enable(bm, e, HULL_FLAG_HOLE);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE);
}
}
@@ -578,11 +581,17 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op)
/* Tag input elements */
BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) {
- BMO_elem_flag_enable(bm, ele, HULL_FLAG_INPUT);
-
+
/* Mark all vertices as interior to begin with */
- if (ele->head.htype == BM_VERT)
- BMO_elem_flag_enable(bm, ele, HULL_FLAG_INTERIOR_ELE);
+ if (ele->head.htype == BM_VERT) {
+ BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE);
+ }
+ else if (ele->head.htype == BM_EDGE) {
+ BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT);
+ }
+ else {
+ BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT);
+ }
}
hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index ef5d90e6acb..c52c608e671 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -313,7 +313,7 @@ static void bmo_face_inset_individual(
l_iter->next->v,
l_iter->v,
f, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
+ BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
/* copy loop data */
l_other = l_iter->radial_next;
@@ -1037,7 +1037,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* no need to check doubles, we KNOW there won't be any */
/* yes - reverse face is correct in this case */
f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
- BMO_elem_flag_enable(bm, f, ELE_NEW);
+ BMO_face_flag_enable(bm, f, ELE_NEW);
/* copy for loop data, otherwise UV's and vcols are no good.
* tiny speedup here we could be more clever and copy from known adjacent data
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 3718f14276c..bc620e4a020 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -315,7 +315,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
/* flag all edges of all input face */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
- BMO_elem_flag_enable(bm, f, FACE_INPUT);
+ BMO_face_flag_enable(bm, f, FACE_INPUT);
}
}
@@ -323,11 +323,11 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMFace *f_a, *f_b;
if (BM_edge_face_pair(e, &f_a, &f_b) &&
- (BMO_elem_flag_test(bm, f_a, FACE_INPUT) &&
- BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
+ (BMO_face_flag_test(bm, f_a, FACE_INPUT) &&
+ BMO_face_flag_test(bm, f_b, FACE_INPUT)))
{
if (!bm_edge_is_delimit(e, &delimit_data)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
totedge_tag++;
}
}
@@ -345,7 +345,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
const BMVert *verts[4];
float error;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
bm_edge_to_quad_verts(e, verts);
@@ -372,7 +372,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BMFace *f_new;
f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 6044960265b..f0738303d5c 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -111,7 +111,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f
madd_v3_v3fl(cent, f_cent, cent_fac * f_area);
cent_area_accum += f_area;
- BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0);
+ BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0);
BLI_assert(BM_face_is_normal_valid(faces[i]));
}
@@ -209,7 +209,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip);
if (is_flip) {
- BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP);
+ BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP);
}
/* now that we've found our starting face, make all connected faces
@@ -219,10 +219,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
BLI_LINKSTACK_INIT(fstack);
BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]);
- BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP);
+ BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP);
while ((f = BLI_LINKSTACK_POP(fstack))) {
- const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP);
+ const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@@ -230,9 +230,9 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
BMLoop *l_other = l_iter->radial_next;
if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) {
- if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) {
- BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP);
- BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
+ if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) {
+ BMO_face_flag_enable(bm, l_other->f, FACE_TEMP);
+ BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
BLI_LINKSTACK_PUSH(fstack, l_other->f);
}
}
@@ -243,10 +243,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
/* apply flipping to oflag'd faces */
for (i = 0; i < faces_len; i++) {
- if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
+ if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
BM_face_normal_flip(bm, faces[i]);
}
- BMO_elem_flag_disable(bm, faces[i], FACE_TEMP);
+ BMO_face_flag_disable(bm, faces[i], FACE_TEMP);
}
}
@@ -284,7 +284,7 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
if (is_calc == false) {
- is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
+ is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
}
}
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
index 8f4bc5ef3ad..7a6f779b34f 100644
--- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -178,7 +178,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
#ifdef USE_CAP_OPTION
if (v_edges_num_untag == 1) {
- BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT);
}
CLAMP_MIN(v_edges_max, v_edges_num);
@@ -201,7 +201,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
(BM_elem_index_get(l->prev->v) == -1))
{
#ifdef USE_CAP_OPTION
- if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
+ if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
#endif
{
BMLoop *l_new;
@@ -209,7 +209,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BLI_assert(f_cmp == l->f);
BLI_assert(f_cmp != l_new->f);
UNUSED_VARS_NDEBUG(f_cmp);
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
}
}
else if (l->f->len > 4) {
@@ -222,7 +222,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true);
BLI_assert(f_cmp == l->f);
BLI_assert(f_cmp != l_new->f);
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
BM_elem_flag_disable(l->f, BM_ELEM_TAG);
}
else {
@@ -230,7 +230,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BMLoop *l_new;
bm_face_split_walk_back(bm, l, &l_new);
do {
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
l_new = l_new->next;
} while (BM_vert_is_edge_pair(l_new->v));
BM_elem_flag_disable(l->f, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c
index 2856d3d18a6..a0951455fb4 100644
--- a/source/blender/bmesh/operators/bmo_planar_faces.c
+++ b/source/blender/bmesh/operators/bmo_planar_faces.c
@@ -71,13 +71,13 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
- BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
+ if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
+ BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
shared_vert_num += 1;
}
} while ((l_iter = l_iter->next) != l_first);
- BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
}
vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP);
@@ -91,10 +91,10 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
BMLoop *l_iter, *l_first;
float plane[4];
- if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) {
+ if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) {
continue;
}
- BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST);
BLI_assert(f->len != 3);
@@ -130,7 +130,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
BMIter iter;
if (len_squared_v3v3(v->co, va->co) > eps_sq) {
- BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST);
interp_v3_v3v3(v->co, v->co, va->co, fac);
changed = true;
}
@@ -138,7 +138,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
/* tag for re-calculation */
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
if (f->len != 3) {
- BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c
index 4d86d6e8e5b..32ad25b7b82 100644
--- a/source/blender/bmesh/operators/bmo_poke.c
+++ b/source/blender/bmesh/operators/bmo_poke.c
@@ -87,7 +87,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
bm_face_calc_center_fn(f, f_center);
v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v_center, ELE_NEW);
+ BMO_vert_flag_enable(bm, v_center, ELE_NEW);
if (cd_loop_mdisp_offset != -1) {
if (center_mode == BMOP_POKE_MEAN) {
@@ -128,7 +128,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
BM_elem_attrs_copy(bm, bm, l_iter, l_new);
BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next);
- BMO_elem_flag_enable(bm, f_new, ELE_NEW);
+ BMO_face_flag_enable(bm, f_new, ELE_NEW);
if (cd_loop_mdisp_offset != -1) {
float f_new_center[3];
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index b120b48447f..d2b9fa9efa3 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -259,7 +259,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
vec[0] = ((x * xtot_inv2) - 1.0f) * dia;
mul_v3_m4v3(tvec, mat, vec);
varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, varr[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, varr[i], VERT_MARK);
i++;
}
}
@@ -277,7 +277,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
}
@@ -315,7 +315,7 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig
BLI_assert(cd_loop_uv_offset != -1);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
@@ -380,11 +380,11 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
vec[1] = dia * sinf(phi);
vec[2] = dia * cosf(phi);
eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, eve, VERT_MARK);
+ BMO_vert_flag_enable(bm, eve, VERT_MARK);
if (a != 0) {
e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, e, EDGE_ORIG);
+ BMO_edge_flag_enable(bm, e, EDGE_ORIG);
}
phi += phid;
@@ -442,14 +442,14 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
bool valid = true;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) {
valid = false;
break;
}
}
if (valid) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -458,7 +458,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
/* and now do imat */
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, eve, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, eve, VERT_MARK)) {
mul_m4_v3(mat, eve->co);
}
}
@@ -493,7 +493,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
vec[2] = dia_div * icovert[a][2];
eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, eva[a], VERT_MARK);
+ BMO_vert_flag_enable(bm, eva[a], VERT_MARK);
}
for (a = 0; a < 20; a++) {
@@ -507,10 +507,10 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) {
- BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, l->e, EDGE_MARK);
}
- BMO_elem_flag_enable(bm, eftemp, FACE_MARK);
+ BMO_face_flag_enable(bm, eftemp, FACE_MARK);
}
if (subdiv > 1) {
@@ -540,14 +540,14 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
bool valid = true;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) {
valid = false;
break;
}
}
if (valid) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -556,7 +556,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
/* must transform after because of sphere subdivision */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
mul_m4_v3(mat, v->co);
}
}
@@ -626,7 +626,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset);
@@ -650,7 +650,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
v[1] = monkeyv[i][2] / -128.0;
tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, tv[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, tv[i], VERT_MARK);
if (fabsf(v[0] = -v[0]) < 0.001f) {
tv[monkeynv + i] = tv[i];
@@ -661,7 +661,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
tv[monkeynv + i] = eve;
}
- BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
+ BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
mul_m4_v3(mat, tv[i]->co);
}
@@ -713,7 +713,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, cent1, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent1, VERT_MARK);
}
for (a = 0; a < segs; a++, phi += phid) {
@@ -724,7 +724,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, v1, VERT_MARK);
if (lastv1)
BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP);
@@ -733,7 +733,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMFace *f;
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
if (!firstv1)
@@ -751,7 +751,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMFace *f;
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
if (calc_uvs) {
BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
@@ -791,7 +791,7 @@ void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, con
invert_m4_m4(inv_mat, mat);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -845,8 +845,8 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, cent1, VERT_MARK);
- BMO_elem_flag_enable(bm, cent2, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent1, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent2, VERT_MARK);
}
for (a = 0; a < segs; a++, phi += phid) {
@@ -862,27 +862,27 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v1, VERT_MARK);
- BMO_elem_flag_enable(bm, v2, VERT_MARK);
+ BMO_vert_flag_enable(bm, v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, v2, VERT_MARK);
if (a) {
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
else {
@@ -900,20 +900,20 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
if (calc_uvs) {
@@ -981,7 +981,7 @@ void BM_mesh_calc_uvs_cone(
y = 1.0f - uv_height;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
if (f->len == 4 && radius_top && radius_bottom) {
@@ -1063,7 +1063,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
float vec[3] = {(float)x * off, (float)y * off, (float)z * off};
mul_m4_v3(mat, vec);
verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, verts[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, verts[i], VERT_MARK);
i++;
}
}
@@ -1080,7 +1080,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -1117,7 +1117,7 @@ void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag)) {
+ if (!BMO_face_flag_test(bm, f, oflag)) {
continue;
}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index c58b4814726..6da591b23a0 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -98,7 +98,7 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
{
#define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \
v_map = l_init->v; \
- is_del = BMO_elem_flag_test_bool(bm, v_map, ELE_DEL); \
+ is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \
if (is_del) { \
v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \
} ((void)0)
@@ -131,12 +131,12 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
}
if (e_new) {
- if (UNLIKELY(BMO_elem_flag_test(bm, v_curr, VERT_IN_FACE))) {
+ if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) {
/* we can't make the face, bail out */
STACK_CLEAR(edges);
goto finally;
}
- BMO_elem_flag_enable(bm, v_curr, VERT_IN_FACE);
+ BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE);
STACK_PUSH(edges, e_new);
STACK_PUSH(loops, l_curr);
@@ -155,7 +155,7 @@ finally:
{
unsigned int i;
for (i = 0; i < STACK_SIZE(verts); i++) {
- BMO_elem_flag_disable(bm, verts[i], VERT_IN_FACE);
+ BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE);
}
}
@@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
/* mark merge verts for deletion */
BM_ITER_MESH (v1, &iter, bm, BM_VERTS_OF_MESH) {
if ((v2 = BMO_slot_map_elem_get(slot_targetmap, v1))) {
- BMO_elem_flag_enable(bm, v1, ELE_DEL);
+ BMO_vert_flag_enable(bm, v1, ELE_DEL);
/* merge the vertex flags, else we get randomly selected/unselected verts */
BM_elem_flag_merge(v1, v2);
@@ -212,8 +212,8 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
}
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- const bool is_del_v1 = BMO_elem_flag_test_bool(bm, (v1 = e->v1), ELE_DEL);
- const bool is_del_v2 = BMO_elem_flag_test_bool(bm, (v2 = e->v2), ELE_DEL);
+ const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL);
+ const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL);
if (is_del_v1 || is_del_v2) {
if (is_del_v1)
@@ -222,7 +222,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
v2 = BMO_slot_map_elem_get(slot_targetmap, v2);
if (v1 == v2) {
- BMO_elem_flag_enable(bm, e, EDGE_COL);
+ BMO_edge_flag_enable(bm, e, EDGE_COL);
}
else {
/* always merge flags, even for edges we already created */
@@ -233,7 +233,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
BM_elem_flag_merge(e_new, e);
}
- BMO_elem_flag_enable(bm, e, ELE_DEL);
+ BMO_edge_flag_enable(bm, e, ELE_DEL);
}
}
@@ -244,16 +244,16 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
int edge_collapse = 0;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) {
+ if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) {
vert_delete = true;
}
- if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) {
+ if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) {
edge_collapse++;
}
}
if (vert_delete) {
- BMO_elem_flag_enable(bm, f, ELE_DEL);
+ BMO_face_flag_enable(bm, f, ELE_DEL);
if (f->len - edge_collapse >= 3) {
BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap);
@@ -261,8 +261,12 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
/* do this so we don't need to return a list of created faces */
if (f_new) {
bmesh_face_swap_data(f_new, f);
- SWAP(BMFlagLayer *, f->oflags, f_new->oflags);
- BMO_elem_flag_disable(bm, f, ELE_DEL);
+
+ if (bm->use_toolflags) {
+ SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags);
+ }
+
+ BMO_face_flag_disable(bm, f, ELE_DEL);
BM_face_kill(bm, f_new);
}
@@ -439,7 +443,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
float min[3], max[3], center[3];
BMVert *v_tar;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
BLI_assert(BLI_stack_is_empty(edge_stack));
@@ -510,7 +514,7 @@ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short ofl
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->e, oflag)) {
+ if (BMO_edge_flag_test(bm, l->e, oflag)) {
/* walk */
BLI_assert(BLI_stack_is_empty(block_stack));
@@ -606,7 +610,7 @@ static void bmesh_find_doubles_common(
for (i = 0; i < verts_len; i++) {
BMVert *v_check = verts[i];
- if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) {
+ if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) {
continue;
}
@@ -614,7 +618,7 @@ static void bmesh_find_doubles_common(
BMVert *v_other = verts[j];
/* a match has already been found, (we could check which is best, for now don't) */
- if (BMO_elem_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) {
+ if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) {
continue;
}
@@ -628,19 +632,19 @@ static void bmesh_find_doubles_common(
}
if (keepvert) {
- if (BMO_elem_flag_test(bm, v_other, VERT_KEEP) == BMO_elem_flag_test(bm, v_check, VERT_KEEP))
+ if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP))
continue;
}
if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) {
/* If one vert is marked as keep, make sure it will be the target */
- if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) {
+ if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) {
SWAP(BMVert *, v_check, v_other);
}
- BMO_elem_flag_enable(bm, v_other, VERT_DOUBLE);
- BMO_elem_flag_enable(bm, v_check, VERT_TARGET);
+ BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE);
+ BMO_vert_flag_enable(bm, v_check, VERT_TARGET);
BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check);
}
@@ -683,8 +687,8 @@ void bmo_automerge_exec(BMesh *bm, BMOperator *op)
* as VERT_KEEP. */
BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN);
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_elem_flag_test(bm, v, VERT_IN)) {
- BMO_elem_flag_enable(bm, v, VERT_KEEP);
+ if (!BMO_vert_flag_test(bm, v, VERT_IN)) {
+ BMO_vert_flag_enable(bm, v, VERT_KEEP);
}
}
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index 708d57a7a08..454d6d8c6c8 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -121,8 +121,8 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
* and n is the total number of faces
*/
BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
- if (!BMO_elem_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
- BMO_elem_flag_enable(bm, fs, FACE_MARK);
+ if (!BMO_face_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
+ BMO_face_flag_enable(bm, fs, FACE_MARK);
num_sels++;
}
}
@@ -134,7 +134,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
/* loop through all the faces and fill the faces/indices structure */
BM_ITER_MESH (fm, &fm_iter, bm, BM_FACES_OF_MESH) {
f_ext[i].f = fm;
- if (BMO_elem_flag_test(bm, fm, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, fm, FACE_MARK)) {
indices[idx] = i;
idx++;
}
@@ -179,21 +179,21 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
/* now select the rest (if any) */
for (i = 0; i < num_total; i++) {
fm = f_ext[i].f;
- if (!BMO_elem_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) {
+ if (!BMO_face_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
fs = f_ext[indices[idx]].f;
switch (type) {
case SIMFACE_MATERIAL:
if (fm->mat_nr == fs->mat_nr) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
case SIMFACE_IMAGE:
if (f_ext[i].t == f_ext[indices[idx]].t) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -201,7 +201,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_NORMAL:
angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */
if (angle <= thresh_radians) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -218,7 +218,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
if (angle <= thresh_radians) { /* and dot product difference -> 0 */
delta_fl = f_ext[i].d - (f_ext[indices[idx]].d * sign);
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
}
@@ -227,7 +227,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_AREA:
delta_fl = f_ext[i].area - f_ext[indices[idx]].area;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -235,7 +235,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_SIDES:
delta_i = fm->len - fs->len;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -243,14 +243,14 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_PERIMETER:
delta_fl = f_ext[i].perim - f_ext[indices[idx]].perim;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
case SIMFACE_SMOOTH:
if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -263,7 +263,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE);
if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
}
@@ -350,7 +350,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* iterate through all selected edges and mark them */
BMO_ITER (es, &es_iter, op->slots_in, "edges", BM_EDGE) {
- BMO_elem_flag_enable(bm, es, EDGE_MARK);
+ BMO_edge_flag_enable(bm, es, EDGE_MARK);
num_sels++;
}
@@ -361,7 +361,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* loop through all the edges and fill the edges/indices structure */
BM_ITER_MESH (e, &e_iter, bm, BM_EDGES_OF_MESH) {
e_ext[i].e = e;
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
indices[idx] = i;
idx++;
}
@@ -397,7 +397,9 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* select the edges if any */
for (i = 0; i < num_total; i++) {
e = e_ext[i].e;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
es = e_ext[indices[idx]].e;
@@ -405,7 +407,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_LENGTH:
delta_fl = e_ext[i].length - e_ext[indices[idx]].length;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -418,7 +420,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
angle = fabsf(angle - (float)M_PI);
if (angle / (float)M_PI_2 <= thresh) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -426,7 +428,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_FACE:
delta_i = e_ext[i].faces - e_ext[indices[idx]].faces;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -435,7 +437,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
if (e_ext[i].faces == 2) {
if (e_ext[indices[idx]].faces == 2) {
if (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -454,7 +456,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
delta_fl = *c1 - *c2;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -469,7 +471,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
delta_fl = *c1 - *c2;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -477,14 +479,14 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_SEAM:
if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
case SIMEDGE_SHARP:
if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -497,7 +499,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
fed2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_FREESTYLE_EDGE);
if (fed1 && fed2 && (fed1->flag & FREESTYLE_EDGE_MARK) == (fed2->flag & FREESTYLE_EDGE_MARK)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -562,7 +564,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* iterate through all selected edges and mark them */
BMO_ITER (vs, &vs_iter, op->slots_in, "verts", BM_VERT) {
- BMO_elem_flag_enable(bm, vs, VERT_MARK);
+ BMO_vert_flag_enable(bm, vs, VERT_MARK);
num_sels++;
}
@@ -573,7 +575,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* loop through all the vertices and fill the vertices/indices structure */
BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) {
v_ext[i].v = v;
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
indices[idx] = i;
idx++;
}
@@ -599,7 +601,9 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* select the vertices if any */
for (i = 0; i < num_total; i++) {
v = v_ext[i].v;
- if (!BMO_elem_flag_test(bm, v, VERT_MARK) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK) &&
+ !BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
vs = v_ext[indices[idx]].v;
@@ -607,7 +611,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
case SIMVERT_NORMAL:
/* compare the angle between the normals */
if (angle_normalized_v3v3(v->no, vs->no) <= thresh_radians) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
@@ -615,7 +619,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* number of adjacent faces */
delta_i = v_ext[i].num_faces - v_ext[indices[idx]].num_faces;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
@@ -623,7 +627,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
case SIMVERT_VGROUP:
if (v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL) {
if (defvert_find_shared(v_ext[i].dvert, v_ext[indices[idx]].dvert) != -1) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
}
@@ -632,7 +636,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* number of adjacent edges */
delta_i = v_ext[i].num_edges - v_ext[indices[idx]].num_edges;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 38fa2cfdcc8..894129b4a33 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -254,8 +254,7 @@ static void alter_co(
copy_v3_v3(co, v->co);
if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
- normalize_v3(co);
- mul_v3_fl(co, params->smooth);
+ normalize_v3_length(co, params->smooth);
}
else if (params->use_smooth) {
/* calculating twice and blending gives smoother results,
@@ -384,7 +383,7 @@ static BMVert *bm_subdivide_edge_addvert(
v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
- BMO_elem_flag_enable(bm, v_new, ELE_INNER);
+ BMO_vert_flag_enable(bm, v_new, ELE_INNER);
/* offset for smooth or sphere or fractal */
alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
@@ -419,7 +418,7 @@ static BMVert *subdivide_edge_num(
BMVert *v_new;
float factor_edge_split, factor_subd;
- if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
+ if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
factor_subd = 0.0f;
}
@@ -449,9 +448,9 @@ static void bm_subdivide_multicut(
for (i = 0; i < numcuts; i++) {
v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
- BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
- BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
- BMO_elem_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT);
+ BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
+ BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
+ BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT);
BM_CHECK_ELEMENT(v);
if (v->e) BM_CHECK_ELEMENT(v->e);
@@ -698,8 +697,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
if (!e)
continue;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
v1 = lines[(i + 1) * s] = verts[a];
@@ -711,7 +710,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
BMESH_ASSERT(v != NULL);
- BMO_elem_flag_enable(bm, e_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e_new, ELE_INNER);
lines[(i + 1) * s + a + 1] = v;
}
}
@@ -724,8 +723,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
if (!e)
continue;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
}
}
@@ -802,8 +801,8 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
if (!e) goto cleanup;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
lines[i + 1][0] = verts[a];
lines[i + 1][i + 1] = verts[b];
@@ -817,7 +816,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
lines[i + 1][j + 1] = v;
- BMO_elem_flag_enable(bm, e_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e_new, ELE_INNER);
}
}
@@ -837,13 +836,13 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
for (j = 0; j < i; j++) {
e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new);
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new);
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
}
}
@@ -1023,7 +1022,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
edges[i] = l_new->e;
verts[i] = l_new->v;
- if (BMO_elem_flag_test(bm, edges[i], SUBD_SPLIT)) {
+ if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) {
if (!e1) e1 = edges[i];
else e2 = edges[i];
@@ -1043,13 +1042,13 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
}
- if (BMO_elem_flag_test(bm, face, FACE_CUSTOMFILL)) {
+ if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) {
pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face);
for (i = 0; i < pat->len; i++) {
matched = 1;
for (j = 0; j < pat->len; j++) {
a = (j + i) % pat->len;
- if ((!!BMO_elem_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) {
+ if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) {
matched = 0;
break;
}
@@ -1062,7 +1061,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
fd->start = verts[i];
fd->face = face;
fd->totedgesel = totesel;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
break;
}
}
@@ -1082,7 +1081,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
matched = 1;
for (b = 0; b < pat->len; b++) {
j = (b + a) % pat->len;
- if ((!!BMO_elem_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) {
+ if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) {
matched = 0;
break;
}
@@ -1094,7 +1093,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
if (matched) {
SubDFaceData *fd;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
fd = BLI_stack_push_r(facedata);
fd->pat = pat;
@@ -1110,7 +1109,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
if (!matched && totesel) {
SubDFaceData *fd;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
/* must initialize all members here */
fd = BLI_stack_push_r(facedata);
@@ -1162,22 +1161,22 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
/* find the boundary of one of the split edges */
for (a = 1; a < vlen; a++) {
- if (!BMO_elem_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
- BMO_elem_flag_test(bm, loops[a]->v, ELE_INNER))
+ if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
+ BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER))
{
break;
}
}
- if (BMO_elem_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
+ if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
b = (a + numcuts + 1) % vlen;
}
else {
/* find the boundary of the other edge. */
for (j = 0; j < vlen; j++) {
b = (j + a + numcuts + 1) % vlen;
- if (!BMO_elem_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
- BMO_elem_flag_test(bm, loops[b]->v, ELE_INNER))
+ if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
+ BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER))
{
break;
}
@@ -1245,7 +1244,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL);
f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false);
if (f_new) {
- BMO_elem_flag_enable(bm, l_new->e, ELE_INNER);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_INNER);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index b5a95ad6283..b4a77bf1a38 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -128,7 +128,7 @@ static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, c
{
LinkData *node = BM_edgeloop_verts_get(el_store)->first;
do {
- BMO_elem_flag_set(bm, (BMVert *)node->data, oflag, tag);
+ BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag);
} while ((node = node->next));
}
@@ -137,7 +137,7 @@ static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag)
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (!BMO_elem_flag_test(bm, l_iter->v, oflag)) {
+ if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) {
return false;
}
} while ((l_iter = l_iter->next) != l_first);
@@ -150,7 +150,7 @@ static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v)
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
return true;
@@ -243,7 +243,7 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim)
BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data;
BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
struct BMEdgeLoopStore *el_store_other;
BMVert *v_other = BM_edge_other_vert(e, v);
GHashPair pair_test;
@@ -339,7 +339,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
if (UNLIKELY(BM_edge_is_wire(e))) {
/* pass - this may confuse things */
}
- else if (BMO_elem_flag_test(bm, e, EDGE_RIM)) {
+ else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
@@ -347,7 +347,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
float no[3];
// BM_face_normal_update(l->f);
BM_edge_calc_face_tangent(e, l, no);
- if (BMO_elem_flag_test(bm, l->f, FACE_SHARED)) {
+ if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) {
add_v3_v3(no_inner, no);
found_inner = true;
}
@@ -356,7 +356,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
found_outer = true;
/* other side is used too, blend midway */
- if (BMO_elem_flag_test(bm, l->f, FACE_OUT)) {
+ if (BMO_face_flag_test(bm, l->f, FACE_OUT)) {
found_outer_tag = true;
}
}
@@ -400,9 +400,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i
l_iter = l_first = e->l;
do {
- if (!BMO_elem_flag_test(bm, l_iter->f, FACE_SHARED)) {
+ if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) {
if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) {
- BMO_elem_flag_enable(bm, l_iter->f, FACE_SHARED);
+ BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED);
}
}
} while ((l_iter = l_iter->radial_next) != l_first);
@@ -422,7 +422,7 @@ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsig
l_iter = l_first = e->l;
do {
- BMO_elem_flag_disable(bm, l_iter->f, FACE_SHARED);
+ BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED);
} while ((l_iter = l_iter->radial_next) != l_first);
}
}
@@ -834,8 +834,8 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
if (l_new->f->len < l_new->radial_next->f->len) {
l_new = l_new->radial_next;
}
- BMO_elem_flag_enable(bm, l_new->f, FACE_OUT);
- BMO_elem_flag_enable(bm, l_new->radial_next->f, FACE_OUT);
+ BMO_face_flag_enable(bm, l_new->f, FACE_OUT);
+ BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT);
}
}
@@ -903,7 +903,7 @@ static void bm_edgering_pair_order(
node = lb_a->first;
BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
v_other = BM_edge_other_vert(e, (BMVert *)node->data);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
break;
@@ -938,7 +938,7 @@ static void bm_edgering_pair_order(
/* if we dont share and edge - flip */
BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data,
((LinkData *)lb_b->first)->data);
- if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) {
BM_edgeloop_flip(bm, el_store_b);
}
}
@@ -983,19 +983,19 @@ static void bm_edgering_pair_subdiv(
BMIter eiter;
BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EDGE_IN_STACK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) {
BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
BMIter fiter;
- BMO_elem_flag_enable(bm, e, EDGE_IN_STACK);
+ BMO_edge_flag_enable(bm, e, EDGE_IN_STACK);
STACK_PUSH(edges_ring_arr, e);
/* add faces to the stack */
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, FACE_OUT)) {
- if (!BMO_elem_flag_test(bm, f, FACE_IN_STACK)) {
- BMO_elem_flag_enable(bm, f, FACE_IN_STACK);
+ if (BMO_face_flag_test(bm, f, FACE_OUT)) {
+ if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) {
+ BMO_face_flag_enable(bm, f, FACE_IN_STACK);
STACK_PUSH(faces_ring_arr, f);
}
}
@@ -1009,10 +1009,10 @@ static void bm_edgering_pair_subdiv(
/* found opposite edge */
BMVert *v_other;
- BMO_elem_flag_disable(bm, e, EDGE_IN_STACK);
+ BMO_edge_flag_disable(bm, e, EDGE_IN_STACK);
/* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */
- BMO_elem_flag_disable(bm, e, EDGE_RING);
+ BMO_edge_flag_disable(bm, e, EDGE_RING);
v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2;
bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts);
@@ -1021,12 +1021,12 @@ static void bm_edgering_pair_subdiv(
while ((f = STACK_POP(faces_ring_arr))) {
BMLoop *l_iter, *l_first;
- BMO_elem_flag_disable(bm, f, FACE_IN_STACK);
+ BMO_face_flag_disable(bm, f, FACE_IN_STACK);
/* Check each edge of the face */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (BMO_elem_flag_test(bm, l_iter->e, EDGE_RIM)) {
+ if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) {
bm_face_slice(bm, l_iter, cuts);
break;
}
@@ -1064,7 +1064,7 @@ static void bm_edgering_pair_ringsubd(
static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
{
BMesh *bm = bm_v;
- return BMO_elem_flag_test_bool(bm, e, EDGE_RIM);
+ return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
}
@@ -1099,25 +1099,25 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
BMFace *f;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, FACE_OUT)) {
+ if (!BMO_face_flag_test(bm, f, FACE_OUT)) {
BMIter liter;
BMLoop *l;
bool ok = false;
/* check at least 2 edges in the face are rings */
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->e, EDGE_RING) && e != l->e) {
+ if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) {
ok = true;
break;
}
}
if (ok) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->e, EDGE_RING)) {
- BMO_elem_flag_enable(bm, l->e, EDGE_RIM);
+ if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) {
+ BMO_edge_flag_enable(bm, l->e, EDGE_RIM);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 974446f09c0..8938d086c1a 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -91,7 +91,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMVert **e_verts = &e->v1;
unsigned int i;
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
calc_winding = (calc_winding || BM_edge_is_boundary(e));
@@ -132,7 +132,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
add_v3_v3(normal, v->no);
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (e_index == 2) {
e_index = 0;
break;
@@ -203,7 +203,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
- if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
winding_votes += (e->l->v == v_tri[i]) ? 1 : -1;
}
}
@@ -226,10 +226,10 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL,
NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, f, ELE_NEW);
+ BMO_face_flag_enable(bm, f, ELE_NEW);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->e, EDGE_MARK)) {
- BMO_elem_flag_enable(bm, l->e, ELE_NEW);
+ if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) {
+ BMO_edge_flag_enable(bm, l->e, ELE_NEW);
}
}
}
@@ -250,7 +250,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMIter iter;
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, ELE_NEW)) {
+ if (BMO_edge_flag_test(bm, e, ELE_NEW)) {
/* in rare cases the edges face will have already been removed from the edge */
if (LIKELY(e->l)) {
BMFace *f_new = BM_faces_join_pair(
@@ -258,7 +258,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
e->l->radial_next->f, e,
false); /* join faces */
if (f_new) {
- BMO_elem_flag_enable(bm, f_new, ELE_NEW);
+ BMO_face_flag_enable(bm, f_new, ELE_NEW);
BM_edge_kill(bm, e);
}
else {
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index e596032663e..aa1e4bc7523 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -48,7 +48,7 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op)
BMO_slot_vec_get(op->slots_in, "co", vec);
- BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
+ BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW);
}
@@ -74,7 +74,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op)
void bmo_translate_exec(BMesh *bm, BMOperator *op)
{
float mat[4][4], vec[3];
-
+
BMO_slot_vec_get(op->slots_in, "vec", vec);
unit_m4(mat);
@@ -86,7 +86,7 @@ void bmo_translate_exec(BMesh *bm, BMOperator *op)
void bmo_scale_exec(BMesh *bm, BMOperator *op)
{
float mat[3][3], vec[3];
-
+
BMO_slot_vec_get(op->slots_in, "vec", vec);
unit_m3(mat);
@@ -143,18 +143,18 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
if (BM_edge_face_pair(e, &fa, &fb)) {
/* check we're untouched */
- if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == false &&
- BMO_elem_flag_test(bm, fb, FACE_TAINT) == false)
+ if (BMO_face_flag_test(bm, fa, FACE_TAINT) == false &&
+ BMO_face_flag_test(bm, fb, FACE_TAINT) == false)
{
/* don't touch again (faces will be freed so run before rotating the edge) */
- BMO_elem_flag_enable(bm, fa, FACE_TAINT);
- BMO_elem_flag_enable(bm, fb, FACE_TAINT);
+ BMO_face_flag_enable(bm, fa, FACE_TAINT);
+ BMO_face_flag_enable(bm, fb, FACE_TAINT);
if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) {
- BMO_elem_flag_disable(bm, fa, FACE_TAINT);
- BMO_elem_flag_disable(bm, fb, FACE_TAINT);
+ BMO_face_flag_disable(bm, fa, FACE_TAINT);
+ BMO_face_flag_disable(bm, fb, FACE_TAINT);
#if 0
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
return;
@@ -163,7 +163,7 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
continue;
}
- BMO_elem_flag_enable(bm, e2, EDGE_OUT);
+ BMO_edge_flag_enable(bm, e2, EDGE_OUT);
}
}
}
@@ -184,11 +184,11 @@ static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, con
BMLoop *l_iter;
BMLoop *l_first;
- BMO_elem_flag_set(bm, f, oflag, value);
+ BMO_face_flag_set(bm, f, oflag, value);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- BMO_elem_flag_set(bm, l_iter->e, oflag, value);
- BMO_elem_flag_set(bm, l_iter->v, oflag, value);
+ BMO_edge_flag_set(bm, l_iter->e, oflag, value);
+ BMO_vert_flag_set(bm, l_iter->v, oflag, value);
} while ((l_iter = l_iter->next) != l_first);
}
@@ -210,7 +210,9 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
found = true;
break;
}
@@ -223,9 +225,11 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
- BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
+ if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
+ BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
}
}
@@ -234,7 +238,9 @@ static void bmo_region_extend_expand(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ if (!BMO_face_flag_test(bm, f, SEL_FLAG) &&
+ !BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ {
bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
}
}
@@ -245,9 +251,11 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
- BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
+ if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
+ BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
}
}
@@ -269,10 +277,10 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
!BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
{
- BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
+ BMO_face_flag_enable(bm, f_other, SEL_FLAG);
}
}
}
@@ -281,10 +289,10 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
!BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
{
- BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
+ BMO_face_flag_enable(bm, f_other, SEL_FLAG);
}
}
}
@@ -310,7 +318,7 @@ static void bmo_region_extend_contract(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
found = true;
break;
}
@@ -321,7 +329,7 @@ static void bmo_region_extend_contract(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_ORIG)) {
+ if (!BMO_face_flag_test(bm, f, SEL_ORIG)) {
found = true;
break;
}
@@ -334,7 +342,7 @@ static void bmo_region_extend_contract(
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
found = true;
break;
}
@@ -347,10 +355,10 @@ static void bmo_region_extend_contract(
BMIter eiter;
BMEdge *e;
- BMO_elem_flag_enable(bm, v, SEL_FLAG);
+ BMO_vert_flag_enable(bm, v, SEL_FLAG);
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
}
}
}
@@ -369,8 +377,8 @@ static void bmo_region_extend_contract(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
- BMO_elem_flag_enable(bm, f, SEL_FLAG);
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
+ BMO_face_flag_enable(bm, f, SEL_FLAG);
break;
}
}
@@ -380,8 +388,8 @@ static void bmo_region_extend_contract(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
- BMO_elem_flag_enable(bm, f, SEL_FLAG);
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
+ BMO_face_flag_enable(bm, f, SEL_FLAG);
break;
}
}
@@ -420,7 +428,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
const float fac = BMO_slot_float_get(op->slots_in, "factor");
int i, j, clipx, clipy, clipz;
int xaxis, yaxis, zaxis;
-
+
clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x");
clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y");
clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z");
@@ -441,7 +449,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
add_v3_v3v3(co, co, co2);
j += 1;
}
-
+
if (!j) {
copy_v3_v3(co, v->co);
i++;
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 19fe492c670..3e3a6547b75 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -424,11 +424,13 @@ void BM_mesh_beautify_fill(
flag, method);
/* update flags */
- if (oflag_edge)
- BMO_elem_flag_enable(bm, e, oflag_edge);
+ if (oflag_edge) {
+ BMO_edge_flag_enable(bm, e, oflag_edge);
+ }
+
if (oflag_face) {
- BMO_elem_flag_enable(bm, e->l->f, oflag_face);
- BMO_elem_flag_enable(bm, e->l->radial_next->f, oflag_face);
+ BMO_face_flag_enable(bm, e->l->f, oflag_face);
+ BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
}
}
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 0ed1dffcafb..4dc1c8a9f00 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -1849,11 +1849,11 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
do {
BLI_assert(e->is_bev);
/* Make the BoundVert for the right side of e; other side will be made
- * when the beveled edge to the left of e is handled.
- * Analyze edges until next beveled edge.
- * They are either "in plane" (preceding and subsequent faces are coplanar)
- * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
- * along one of those if possible. */
+ * when the beveled edge to the left of e is handled.
+ * Analyze edges until next beveled edge.
+ * They are either "in plane" (preceding and subsequent faces are coplanar)
+ * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
+ * along one of those if possible. */
nip = nnip = 0; /* counts of in-plane / not-in-plane */
enip = eip = NULL; /* representatives of each */
for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 9fb6d39a008..51b92a3c45e 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -155,9 +155,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, l_new->e, oflag_center);
- BMO_elem_flag_enable(bm, l_new->f, oflag_center);
- BMO_elem_flag_enable(bm, f, oflag_center);
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center);
+ BMO_face_flag_enable(bm, l_new->f, oflag_center);
+ BMO_face_flag_enable(bm, f, oflag_center);
}
}
}
@@ -270,9 +270,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
if (l_new) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, l_new->e, oflag_center);
- BMO_elem_flag_enable(bm, l_new->f, oflag_center);
- BMO_elem_flag_enable(bm, face_split_arr[j], oflag_center);
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center);
+ BMO_face_flag_enable(bm, l_new->f, oflag_center);
+ BMO_face_flag_enable(bm, face_split_arr[j], oflag_center);
}
}
@@ -372,7 +372,7 @@ void BM_mesh_bisect_plane(
if (BM_VERT_DIR(v) == 0) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, v, oflag_center);
+ BMO_vert_flag_enable(bm, v, oflag_center);
}
if (use_snap_center) {
closest_to_plane_v3(v->co, plane, v->co);
@@ -407,7 +407,7 @@ void BM_mesh_bisect_plane(
v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
vert_is_center_enable(v_new);
if (oflag_center) {
- BMO_elem_flag_enable(bm, v_new, oflag_center);
+ BMO_vert_flag_enable(bm, v_new, oflag_center);
}
BM_VERT_DIR(v_new) = 0;
@@ -439,7 +439,7 @@ void BM_mesh_bisect_plane(
/* if both verts are on the center - tag it */
if (oflag_center) {
if (side[0] == 0 && side[1] == 0) {
- BMO_elem_flag_enable(bm, e, oflag_center);
+ BMO_edge_flag_enable(bm, e, oflag_center);
}
}
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index ad35d57f35b..978cceee37c 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -335,7 +335,7 @@ void BM_mesh_decimate_dissolve_ex(
/* update normal */
BM_face_normal_update(f_new);
if (oflag_out) {
- BMO_elem_flag_enable(bm, f_new, oflag_out);
+ BMO_face_flag_enable(bm, f_new, oflag_out);
}
/* re-calculate costs */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index db60b3e15e1..0fc571bc0a8 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -213,7 +213,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
#ifdef USE_WALKER
- BMO_elem_flag_enable(bm, v, ELE_VERT_TAG);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_TAG);
#endif
BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */
}
@@ -238,7 +238,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
#ifdef USE_WALKER
- if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG))
+ if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG))
#endif
{
/* check again incase the topology changed */
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 3a709da78e1..f06f299d381 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -416,7 +416,7 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod
{
fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
- Object *obn = BKE_object_copy(source_ob);
+ Object *obn = BKE_object_copy(G.main, source_ob);
DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
BKE_scene_base_add(sce, obn);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f0984fbc127..649c86edd25 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -357,8 +357,11 @@ void bc_triangulate_mesh(Mesh *me)
bool use_beauty = false;
bool tag_only = false;
int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */
-
- BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+ const struct BMeshCreateParams bm_create_params = {0};
+ BMesh *bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &bm_create_params);
BMeshFromMeshParams bm_from_me_params = {0};
bm_from_me_params.calc_face_normal = true;
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
@@ -370,8 +373,8 @@ void bc_triangulate_mesh(Mesh *me)
}
/*
-* A bone is a leaf when it has no children or all children are not connected.
-*/
+ * A bone is a leaf when it has no children or all children are not connected.
+ */
bool bc_is_leaf_bone(Bone *bone)
{
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
@@ -410,10 +413,10 @@ int bc_set_layer(int bitfield, int layer, bool enable)
}
/**
-* BoneExtended is a helper class needed for the Bone chain finder
-* See ArmatureImporter::fix_leaf_bones()
-* and ArmatureImporter::connect_bone_chains()
-**/
+ * BoneExtended is a helper class needed for the Bone chain finder
+ * See ArmatureImporter::fix_leaf_bones()
+ * and ArmatureImporter::connect_bone_chains()
+ */
BoneExtended::BoneExtended(EditBone *aBone)
{
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index a513954ee0d..ad40b4851fb 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -95,9 +95,9 @@ public:
void execute(WorkPackage *work);
/**
- * @brief determine an image format
- * @param memorybuffer
- */
+ * @brief determine an image format
+ * @param memorybuffer
+ */
static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer);
cl_context getContext() { return this->m_context; }
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index e5b9f58ee93..39147f3ab84 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -187,7 +187,7 @@ void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber)
{
WorkPackage *package = new WorkPackage(group, chunkNumber);
#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
- CPUDevice device;
+ CPUDevice device(0);
device.execute(package);
delete package;
#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
@@ -277,6 +277,7 @@ bool WorkScheduler::hasGPUDevices()
#endif
}
+#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
static void CL_CALLBACK clContextError(const char *errinfo,
const void * /*private_info*/,
size_t /*cb*/,
@@ -284,6 +285,7 @@ static void CL_CALLBACK clContextError(const char *errinfo,
{
printf("OPENCL error: %s\n", errinfo);
}
+#endif
void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
{
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 2bff86b9932..6bf9dbe3e54 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -938,11 +938,6 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
// TODO: "Done" operation
- /* ShapeKeys */
- Key *key = BKE_key_from_object(ob);
- if (key)
- build_shapekeys(key);
-
/* Modifiers */
if (ob->modifiers.first) {
ModifierData *md;
@@ -978,6 +973,12 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
return;
}
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ build_shapekeys(key);
+ }
+
build_animdata(obdata);
/* nodes for result of obdata's evaluation, and geometry evaluation on object */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index d9b1722c064..9ca42e1e7d5 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1299,20 +1299,20 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
}
/* IK Solvers...
- * - These require separate processing steps are pose-level
- * to be executed between chains of bones (i.e. once the
- * base transforms of a bunch of bones is done)
- *
- * - We build relations for these before the dependencies
- * between ops in the same component as it is necessary
- * to check whether such bones are in the same IK chain
- * (or else we get weird issues with either in-chain
- * references, or with bones being parented to IK'd bones)
- *
- * Unsolved Issues:
- * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
- * - Animated chain-lengths are a problem...
- */
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * - We build relations for these before the dependencies
+ * between ops in the same component as it is necessary
+ * to check whether such bones are in the same IK chain
+ * (or else we get weird issues with either in-chain
+ * references, or with bones being parented to IK'd bones)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index b690695ae69..edc258003fb 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2352,7 +2352,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
}
else {
ymin = 0.0f;
- ymax = (float)(-ACHANNEL_HEIGHT);
+ ymax = (float)(-ACHANNEL_HEIGHT(ac));
}
/* convert border-region to view coordinates */
@@ -2368,7 +2368,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
if (ac->datatype == ANIMCONT_NLA)
ymin = ymax - NLACHANNEL_STEP(snla);
else
- ymin = ymax - ACHANNEL_STEP;
+ ymin = ymax - ACHANNEL_STEP(ac);
/* if channel is within border-select region, alter it */
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -2569,7 +2569,7 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
- UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
}
return channel_index;
@@ -2701,6 +2701,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
+ /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
+ if (ob != sce->obedit)
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
@@ -2983,7 +2987,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
* ACHANNEL_HEIGHT_HALF.
*/
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
- UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index);
/* handle mouse-click in the relevant channel then */
notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 554abc6e552..26f2a3ebf9c 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -70,6 +70,7 @@
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
+#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -96,9 +97,30 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
+#include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */
+
/* ************************************************************ */
/* Blender Context <-> Animation Context mapping */
+/* ----------- Private Stuff - General -------------------- */
+
+/* Get vertical scaling factor (i.e. typically used for keyframe size) */
+static void animedit_get_yscale_factor(bAnimContext *ac)
+{
+ bTheme *btheme = UI_GetTheme();
+
+ /* grab scale factor directly from action editor setting
+ * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally
+ * since it is a float, and the theem settings methods can only handle chars.
+ */
+ ac->yscale_fac = btheme->tact.keyframe_scale_fac;
+
+ /* clamp to avoid problems with uninitialised values... */
+ if (ac->yscale_fac < 0.1f)
+ ac->yscale_fac = 1.0f;
+ //printf("yscale_fac = %f\n", ac->yscale_fac);
+}
+
/* ----------- Private Stuff - Action Editor ------------- */
/* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
@@ -351,6 +373,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
ac->spacetype = (sa) ? sa->spacetype : 0;
ac->regiontype = (ar) ? ar->regiontype : 0;
+ /* initialise default y-scale factor */
+ animedit_get_yscale_factor(ac);
+
/* get data context info */
// XXX: if the below fails, try to grab this info from context instead... (to allow for scripting)
return ANIM_animdata_context_getdata(ac);
@@ -1241,7 +1266,7 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee
/* don't include anything from this action if it is linked in from another file,
* and we're getting stuff for editing...
*/
- if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
+ if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED_DATABLOCK(act))
return 0;
/* do groups */
@@ -2633,11 +2658,97 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
return items;
}
+
+/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
+static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode)
+{
+ Object *ob = base->object;
+
+ if (base->object == NULL)
+ return false;
+
+ /* firstly, check if object can be included, by the following factors:
+ * - if only visible, must check for layer and also viewport visibility
+ * --> while tools may demand only visible, user setting takes priority
+ * as user option controls whether sets of channels get included while
+ * tool-flag takes into account collapsed/open channels too
+ * - if only selected, must check if object is selected
+ * - there must be animation data to edit (this is done recursively as we
+ * try to add the channels)
+ */
+ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ /* layer visibility - we check both object and base, since these may not be in sync yet */
+ if ((scene->lay & (ob->lay | base->lay)) == 0)
+ return false;
+
+ /* outliner restrict-flag */
+ if (ob->restrictflag & OB_RESTRICT_VIEW)
+ return false;
+ }
+
+ /* if only F-Curves with visible flags set can be shown, check that
+ * datablock hasn't been set to invisible
+ */
+ if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
+ if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
+ return false;
+ }
+
+ /* check selection and object type filters */
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) {
+ /* only selected should be shown */
+ return false;
+ }
+
+ /* check if object belongs to the filtering group if option to filter
+ * objects by the grouped status is on
+ * - used to ease the process of doing multiple-character choreographies
+ */
+ if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
+ if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ return false;
+ }
+
+ /* no reason to exclude this object... */
+ return true;
+}
+
+/* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */
+static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
+{
+ const Base *b1 = *((const Base **)base1_ptr);
+ const Base *b2 = *((const Base **)base2_ptr);
+
+ return strcmp(b1->object->id.name + 2, b2->object->id.name + 2);
+}
+
+/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
+static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases)
+{
+ /* Create an array with space for all the bases, but only containing the usable ones */
+ size_t tot_bases = BLI_listbase_count(&scene->base);
+ size_t num_bases = 0;
+
+ Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ sorted_bases[num_bases++] = base;
+ }
+ }
+
+ /* Sort this list of pointers (based on the names) */
+ qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp);
+
+ /* Return list of sorted bases */
+ *r_usable_bases = num_bases;
+ return sorted_bases;
+}
+
+
// TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted)
static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
{
- Scene *sce = (Scene *)ads->source;
- Base *base;
+ Scene *scene = (Scene *)ads->source;
size_t items = 0;
/* check that we do indeed have a scene */
@@ -2657,56 +2768,45 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
}
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
- items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode);
-
- /* loop over all bases (i.e.objects) in the scene */
- for (base = sce->base.first; base; base = base->next) {
- /* check if there's an object (all the relevant checks are done in the ob-function) */
- if (base->object) {
- Object *ob = base->object;
-
- /* firstly, check if object can be included, by the following factors:
- * - if only visible, must check for layer and also viewport visibility
- * --> while tools may demand only visible, user setting takes priority
- * as user option controls whether sets of channels get included while
- * tool-flag takes into account collapsed/open channels too
- * - if only selected, must check if object is selected
- * - there must be animation data to edit (this is done recursively as we
- * try to add the channels)
- */
- if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
- /* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((sce->lay & (ob->lay | base->lay)) == 0) continue;
-
- /* outliner restrict-flag */
- if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
- }
-
- /* if only F-Curves with visible flags set can be shown, check that
- * datablock hasn't been set to invisible
- */
- if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
- if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
- continue;
+ items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
+
+ /* If filtering for channel drawing, we want the objects in alphabetical order,
+ * to make it easier to predict where items are in the hierarchy
+ * - This order only really matters if we need to show all channels in the list (e.g. for drawing)
+ * (XXX: What about lingering "active" flags? The order may now become unpredictable)
+ * - Don't do this if this behaviour has been turned off (i.e. due to it being too slow)
+ * - Don't do this if there's just a single object
+ */
+ if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
+ (scene->base.first != scene->base.last))
+ {
+ /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
+ // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort...
+ Base **sorted_bases;
+ size_t num_bases;
+
+ sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases);
+ if (sorted_bases) {
+ /* Add the necessary channels for these bases... */
+ for (size_t i = 0; i < num_bases; i++) {
+ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode);
}
- /* check selection and object type filters */
- if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) {
- /* only selected should be shown */
- continue;
- }
+ // TODO: store something to validate whether any changes are needed?
- /* check if object belongs to the filtering group if option to filter
- * objects by the grouped status is on
- * - used to ease the process of doing multiple-character choreographies
- */
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
- continue;
+ /* free temporary data */
+ MEM_freeN(sorted_bases);
+ }
+ }
+ else {
+ /* Filter and add contents of each base (i.e. object) without them sorting first
+ * NOTE: This saves performance in cases where order doesn't matter
+ */
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ /* since we're still here, this object should be usable */
+ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
-
- /* since we're still here, this object should be usable */
- items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
}
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 6f1883cff55..6e776953356 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -40,6 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -282,6 +283,9 @@ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
ab->modified = 1;
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
+ ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+
return ab;
}
@@ -305,16 +309,28 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
}
- /* check if block needed - same value(s)?
- * -> firstly, handles must have same central value as each other
- * -> secondly, handles which control that section of the curve must be constant
- */
+ /* check if block needed */
if (prev == NULL) return;
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
-
- if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
- if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
+ /* Animator tagged a "moving hold"
+ * - Previous key must also be tagged as a moving hold, otherwise
+ * we're just dealing with the first of a pair, and we don't
+ * want to be creating any phantom holds...
+ */
+ if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD)
+ return;
+ }
+ else {
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
+
+ if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
+ if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ }
/* if there are no blocks already, just add as root */
if (blocks->root == NULL) {
@@ -340,7 +356,13 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
*/
if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
/* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT;
+ if (BEZT_ISSEL_ANY(beztn))
+ ab->sel = SELECT;
+
+ /* XXX: only when the first one was a moving hold? */
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
+ ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+
ab->modified++;
/* done... no need to insert */
@@ -485,7 +507,27 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
/* tweak size of keyframe shape according to type of keyframe
* - 'proper' keyframes have key_type = 0, so get drawn at full size
*/
- hsize -= 0.5f * key_type;
+ switch (key_type) {
+ case BEZT_KEYTYPE_KEYFRAME: /* must be full size */
+ break;
+
+ case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
+ hsize *= 0.85f;
+ break;
+
+ case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */
+ //hsize *= 0.72f;
+ hsize *= 0.95f;
+ break;
+
+ case BEZT_KEYTYPE_EXTREME: /* slightly larger */
+ hsize *= 1.2f;
+ break;
+
+ default:
+ hsize -= 0.5f * key_type;
+ break;
+ }
/* adjust view transform before starting */
glTranslatef(x, y, 0.0f);
@@ -518,6 +560,15 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
break;
}
+ case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
+ {
+ /* XXX: Should these get their own theme options instead? */
+ if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col);
+ else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col);
+
+ inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */
+ break;
+ }
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
default:
{
@@ -557,13 +608,16 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
glTranslatef(-x, -y, 0.0f);
}
-static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, short channelLocked)
+static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked)
{
ActKeyColumn *ak;
ActKeyBlock *ab;
float alpha;
float xscale;
- float iconsize = U.widget_unit / 4.0f;
+
+ const float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
+ const float mhsize = iconsize * 0.7f;
+
glEnable(GL_BLEND);
/* get View2D scaling factor */
@@ -576,6 +630,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
/* draw keyblocks */
if (blocks) {
float sel_color[4], unsel_color[4];
+ float sel_mhcol[4], unsel_mhcol[4];
/* cache colours first */
UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
@@ -584,16 +639,32 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
sel_color[3] *= alpha;
unsel_color[3] *= alpha;
+ copy_v4_v4(sel_mhcol, sel_color);
+ sel_mhcol[3] *= 0.8f;
+ copy_v4_v4(unsel_mhcol, unsel_color);
+ unsel_mhcol[3] *= 0.8f;
+
/* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
for (ab = blocks->first; ab; ab = ab->next) {
if (actkeyblock_is_valid(ab, keys)) {
- /* draw block */
- if (ab->sel)
- glColor4fv(sel_color);
- else
- glColor4fv(unsel_color);
-
- glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) {
+ /* draw "moving hold" long-keyframe block - slightly smaller */
+ if (ab->sel)
+ glColor4fv(sel_mhcol);
+ else
+ glColor4fv(unsel_mhcol);
+
+ glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize);
+ }
+ else {
+ /* draw standard long-keyframe block */
+ if (ab->sel)
+ glColor4fv(sel_color);
+ else
+ glColor4fv(unsel_color);
+
+ glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ }
}
}
}
@@ -619,7 +690,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
/* *************************** Channel Drawing Funcs *************************** */
-void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
+void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -631,13 +702,13 @@ void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
+void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -649,13 +720,13 @@ void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos)
+void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -667,19 +738,19 @@ void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
+void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (fcu->flag & FCURVE_PROTECTED) ||
- ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
- ((adt && adt->action) && (adt->action->id.lib));
+ bool locked = (fcu->flag & FCURVE_PROTECTED) ||
+ ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
+ ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -689,18 +760,18 @@ void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos)
+void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (agrp->flag & AGRP_PROTECTED) ||
- ((adt && adt->action) && (adt->action->id.lib));
+ bool locked = (agrp->flag & AGRP_PROTECTED) ||
+ ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -710,17 +781,17 @@ void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float y
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
+void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (act && act->id.lib != NULL);
+ bool locked = (act && ID_IS_LINKED_DATABLOCK(act));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -730,13 +801,13 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos)
+void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
@@ -746,38 +817,42 @@ void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos
BLI_dlrbTree_linkedlist_sync(&keys);
- draw_keylist(v2d, &keys, NULL, ypos, 0);
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
}
-void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
+void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
+ bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0;
+
BLI_dlrbTree_init(&keys);
gpl_to_keylist(ads, gpl, &keys);
BLI_dlrbTree_linkedlist_sync(&keys);
- draw_keylist(v2d, &keys, NULL, ypos, (gpl->flag & GP_LAYER_LOCKED));
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
}
-void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos)
+void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
-
+
+ bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0;
+
BLI_dlrbTree_init(&keys);
-
+
mask_to_keylist(ads, masklay, &keys);
-
+
BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, ypos, (masklay->flag & MASK_LAYERFLAG_LOCKED));
-
+
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
+
BLI_dlrbTree_free(&keys);
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 7b35a154fc8..4571df0f077 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -1208,6 +1208,13 @@ static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
+ return 0;
+}
+
/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
{
@@ -1221,6 +1228,9 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
return set_keytype_jitter;
+ case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
+ return set_keytype_moving_hold;
+
case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
default:
return set_keytype_keyframe;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index a929507929f..5015829f868 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -86,7 +86,7 @@ void ED_armature_enter_posemode(bContext *C, Base *base)
ReportList *reports = CTX_wm_reports(C);
Object *ob = base->object;
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
return;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index dca9aa3e446..d9a3efa765c 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -183,7 +183,7 @@ static int has_poselib_pose_data_poll(bContext *C)
static int has_poselib_pose_data_for_editing_poll(bContext *C)
{
Object *ob = get_poselib_object(C);
- return (ob && ob->poselib && !ob->poselib->id.lib);
+ return (ob && ob->poselib && !ID_IS_LINKED_DATABLOCK(ob->poselib));
}
/* ----------------------------------- */
@@ -385,7 +385,7 @@ static int poselib_add_poll(bContext *C)
if (ED_operator_posemode(C)) {
Object *ob = get_poselib_object(C);
if (ob) {
- if ((ob->poselib == NULL) || (ob->poselib->id.lib == 0)) {
+ if ((ob->poselib == NULL) || !ID_IS_LINKED_DATABLOCK(ob->poselib)) {
return true;
}
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 420f72fedb3..72b48a32477 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1301,7 +1301,7 @@ static int separate_exec(bContext *C, wmOperator *op)
DAG_relations_tag_update(bmain);
newob = newbase->object;
- newcu = newob->data = BKE_curve_copy(oldcu);
+ newcu = newob->data = BKE_curve_copy(bmain, oldcu);
newcu->editnurb = NULL;
id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */
@@ -6034,9 +6034,8 @@ int join_curve_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(&cu->nurb, &tempbase);
DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
-
- ED_object_editmode_enter(C, EM_WAITCURSOR);
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index a0453f9694d..a61f863b61e 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -77,7 +77,7 @@ static struct {
/* We could have the undo API pass in the previous state, for now store a local list */
ListBase local_links;
-} uf_arraystore = {NULL};
+} uf_arraystore = {{NULL}};
/**
* \param create: When false, only free the arrays.
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index c39a3aa5cfc..f9b479ca03d 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -43,7 +43,9 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "ED_gpencil.h"
@@ -151,7 +153,7 @@ void gpencil_undo_push(bGPdata *gpd)
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
- undo_node->gpd = gpencil_data_duplicate(gpd, true);
+ undo_node->gpd = gpencil_data_duplicate(G.main, gpd, true);
cur_node = undo_node;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index b2c6107ab61..d62625baaa4 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -552,8 +552,8 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
}
/* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
+ * to prevent the stroke from shrinking too much
+ */
if ((i == 0) || (i == gps->totpoints - 1)) {
inf *= 0.1f;
}
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index eacf769270b..1095c770703 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -74,6 +74,7 @@ typedef struct bAnimContext {
short mode; /* editor->mode */
short spacetype; /* sa->spacetype */
short regiontype; /* active region -> type (channels or main) */
+
struct ScrArea *sa; /* editor host */
struct SpaceLink *sl; /* editor data */
struct ARegion *ar; /* region within editor */
@@ -85,6 +86,8 @@ typedef struct bAnimContext {
ListBase *markers; /* active set of markers */
struct ReportList *reports; /* pointer to current reports list */
+
+ float yscale_fac; /* scale factor for height of channels (i.e. based on the size of keyframes) */
} bAnimContext;
/* Main Data container types */
@@ -329,11 +332,11 @@ typedef enum eAnimFilter_Flags {
/* -------------- Channel Defines -------------- */
/* channel heights */
-#define ACHANNEL_FIRST (-0.8f * U.widget_unit)
-#define ACHANNEL_HEIGHT (0.8f * U.widget_unit)
-#define ACHANNEL_HEIGHT_HALF (0.4f * U.widget_unit)
-#define ACHANNEL_SKIP (0.1f * U.widget_unit)
-#define ACHANNEL_STEP (ACHANNEL_HEIGHT + ACHANNEL_SKIP)
+#define ACHANNEL_FIRST(ac) (-0.8f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_HEIGHT_HALF(ac) (0.4f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_SKIP (0.1f * U.widget_unit)
+#define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP)
/* channel widths */
#define ACHANNEL_NAMEWIDTH (10 * U.widget_unit)
@@ -345,7 +348,6 @@ typedef enum eAnimFilter_Flags {
/* -------------- NLA Channel Defines -------------- */
/* NLA channel heights */
-// XXX: NLACHANNEL_FIRST isn't used?
#define NLACHANNEL_FIRST (-0.8f * U.widget_unit)
#define NLACHANNEL_HEIGHT(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit))
#define NLACHANNEL_HEIGHT_HALF(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.4f * U.widget_unit) : (0.6f * U.widget_unit))
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 7d163da0db0..b1f3f012e09 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -80,7 +80,7 @@ typedef struct ActKeyBlock {
/* key-block info */
char sel;
- short handle_type;
+ short flag;
float val;
float start, end;
@@ -89,6 +89,12 @@ typedef struct ActKeyBlock {
short totcurve;
} ActKeyBlock;
+/* ActKeyBlock - Flag */
+typedef enum eActKeyBlock_Flag {
+ /* Key block represents a moving hold */
+ ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
+} eActKeyBlock_Flag;
+
/* *********************** Keyframe Drawing ****************************** */
/* options for keyframe shape drawing */
@@ -108,23 +114,23 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
/* Channel Drawing ------------------ */
/* F-Curve */
-void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos);
+void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac);
/* Action Group Summary */
-void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos);
+void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac);
/* Action Summary */
-void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos);
+void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac);
/* Object Summary */
-void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos);
+void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac);
/* Scene Summary */
-void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
+void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac);
/* DopeSheet Summary */
-void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos);
+void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac);
/* Grease Pencil datablock summary */
-void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos);
+void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac);
/* Grease Pencil Layer */
-void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
+void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac);
/* Mask Layer */
-void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos);
+void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac);
/* Keydata Generation --------------- */
/* F-Curve */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 2c80701bf69..d85b60dcc43 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -1020,6 +1020,7 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC)
DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
DEF_VICO(KEYTYPE_EXTREME_VEC)
DEF_VICO(KEYTYPE_JITTER_VEC)
+DEF_VICO(KEYTYPE_MOVING_HOLD_VEC)
DEF_VICO(COLORSET_01_VEC)
DEF_VICO(COLORSET_02_VEC)
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index dc843952229..a81221ed54b 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -347,6 +347,8 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
// get four color values, scaled to 0.0-1.0 range
void UI_GetThemeColor4fv(int colorid, float col[4]);
+// get four color values, range 0.0-1.0, complete with shading offset for the RGB components
+void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
// get the 3 or 4 byte values
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 2cbc56b14d3..ac7b6428217 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -805,7 +805,7 @@ static int depthdropper_init(bContext *C, wmOperator *op)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d && rv3d->persp == RV3D_CAMOB) {
View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && (((ID *)v3d->camera->data)->lib == NULL)) {
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) {
RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index f941993a9e1..0a0ecf93d17 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -5607,8 +5607,7 @@ static bool ui_numedit_but_HSVCIRCLE(
ui_color_picker_to_rgb_v(hsv, rgb);
if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (rgb[0] || rgb[1] || rgb[2])) {
- normalize_v3(rgb);
- mul_v3_fl(rgb, but->a2);
+ normalize_v3_length(rgb, but->a2);
}
if (use_display_colorspace)
@@ -5684,8 +5683,7 @@ static void ui_ndofedit_but_HSVCIRCLE(
ui_color_picker_to_rgb_v(hsv, data->vec);
if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (data->vec[0] || data->vec[1] || data->vec[2])) {
- normalize_v3(data->vec);
- mul_v3_fl(data->vec, but->a2);
+ normalize_v3_length(data->vec, but->a2);
}
if (use_display_colorspace)
@@ -6014,20 +6012,15 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
CurveMapPoint *cmp;
- float fx, fy, zoomx, zoomy, offsx, offsy;
- float dist, mindist = 200.0f; // 14 pixels radius
+ const float m_xy[2] = {mx, my};
+ float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */
int sel = -1;
- zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr);
- zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr);
- offsx = cumap->curr.xmin;
- offsy = cumap->curr.ymin;
-
if (event->ctrl) {
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
- curvemap_insert(cuma, fx, fy);
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
}
@@ -6035,33 +6028,37 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
/* check for selecting of a point */
cmp = cuma->curve; /* ctrl adds point, new malloc */
for (a = 0; a < cuma->totpoint; a++) {
- fx = but->rect.xmin + zoomx * (cmp[a].x - offsx);
- fy = but->rect.ymin + zoomy * (cmp[a].y - offsy);
- dist = (fx - mx) * (fx - mx) + (fy - my) * (fy - my);
- if (dist < mindist) {
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[a].x);
+ const float dist_sq = len_squared_v2v2(m_xy, f_xy);
+ if (dist_sq < dist_min_sq) {
sel = a;
- mindist = dist;
+ dist_min_sq = dist_sq;
}
}
if (sel == -1) {
int i;
+ float f_xy[2], f_xy_prev[2];
/* if the click didn't select anything, check if it's clicked on the
* curve itself, and if so, add a point */
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
-
cmp = cuma->table;
- /* loop through the curve segment table and find what's near the mouse.
- * 0.05 is kinda arbitrary, but seems to be what works nicely. */
- for (i = 0; i <= CM_TABLE; i++) {
- if ((fabsf(fx - cmp[i].x) < 0.05f) &&
- (fabsf(fy - cmp[i].y) < 0.05f))
- {
-
- curvemap_insert(cuma, fx, fy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x);
+
+ /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */
+ dist_min_sq = SQUARE(8.0f);
+
+ /* loop through the curve segment table and find what's near the mouse. */
+ for (i = 1; i <= CM_TABLE; i++) {
+ copy_v2_v2(f_xy_prev, f_xy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[i].x);
+
+ if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) {
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
+
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
@@ -6070,10 +6067,11 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
cmp = cuma->curve;
/* find newly added point and make it 'sel' */
- for (a = 0; a < cuma->totpoint; a++)
- if (cmp[a].x == fx)
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cmp[a].x == f_xy[0]) {
sel = a;
-
+ }
+ }
break;
}
}
@@ -8722,8 +8720,7 @@ static bool ui_mouse_motion_towards_check(
float delta[2];
sub_v2_v2v2(delta, oldp, cent);
- normalize_v2(delta);
- mul_v2_fl(delta, MENU_TOWARDS_WIGGLE_ROOM);
+ normalize_v2_length(delta, MENU_TOWARDS_WIGGLE_ROOM);
add_v2_v2(oldp, delta);
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 446ac634767..c1d7a9ada96 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -505,6 +505,11 @@ 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_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD);
+}
+
static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
{
bTheme *btheme = UI_GetTheme();
@@ -792,6 +797,7 @@ 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_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01);
def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index ff29a6f8e33..01b10b7b032 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -416,7 +416,7 @@ bool UI_context_copy_to_selected_list(
if ((id_data == NULL) ||
(id_data->tag & LIB_TAG_DOIT) == 0 ||
- (id_data->lib) ||
+ ID_IS_LINKED_DATABLOCK(id_data->lib) ||
(GS(id_data->name) != id_code))
{
BLI_remlink(&lb, link);
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index d4d3e1af1fd..575b32e81e8 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -454,7 +454,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
if (but->rnapoin.id.data) {
ID *id = but->rnapoin.id.data;
- if (id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(id)) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Library: %s"), id->lib->name);
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index cf3a50d632a..7cc7b540cc0 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -301,7 +301,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(id, false)) {
+ if (id_make_local(CTX_data_main(C), id, false)) {
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -453,7 +453,7 @@ static void template_ID(
else {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local"));
- if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib))
+ if (!id_make_local(CTX_data_main(C), id, true /* test */) || (idfrom && idfrom->lib))
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
@@ -473,7 +473,7 @@ static void template_ID(
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
- (id_copy(id, NULL, true) == false) ||
+ (id_copy(CTX_data_main(C), id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
(!editable) ||
/* object in editmode - don't change data */
@@ -939,7 +939,7 @@ static uiLayout *draw_modifier(
}
UI_block_lock_clear(block);
- UI_block_lock_set(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, ob && ID_IS_LINKED_DATABLOCK(ob), ERROR_LIBDATA_MESSAGE);
if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody,
eModifierType_Cloth, eModifierType_Smoke))
@@ -986,7 +986,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
- UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE);
/* find modifier and draw it */
cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
@@ -1214,7 +1214,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
return NULL;
}
- UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE);
/* hrms, the temporal constraint should not draw! */
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
@@ -1576,7 +1576,7 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
block = uiLayoutAbsoluteBlock(layout);
id = cptr.id.data;
- UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE);
colorband_buttons_layout(layout, block, cptr.data, &rect, cb, expand);
@@ -2228,7 +2228,7 @@ void uiTemplateCurveMapping(
cb->prop = prop;
id = cptr.id.data;
- UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE);
curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 5098e701638..02981b543f3 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -3042,7 +3042,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* Now we reduce alpha of the inner color (i.e. the color shown)
- * so that this setting can look greyed out, while retaining
+ * so that this setting can look grayed out, while retaining
* the checkboard (for transparent values). This is needed
* here as the effects of ui_widget_color_disabled() are overwritten.
*/
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e2e2413c717..c8ff335f2a0 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1011,6 +1011,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tact.keyborder, 0, 0, 0, 255);
rgba_char_args_set(btheme->tact.keyborder_select, 0, 0, 0, 255);
+ btheme->tact.keyframe_scale_fac = 1.0f;
+
/* space nla */
btheme->tnla = btheme->tact;
@@ -1471,6 +1473,30 @@ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
col[2] = cp[2];
}
+/* get the color, range 0.0-1.0, complete with shading offset */
+void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
+{
+ int r, g, b, a;
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+
+ r = offset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int) cp[2];
+ CLAMP(b, 0, 255);
+
+ a = (int) cp[3]; /* no shading offset... */
+ CLAMP(a, 0, 255);
+
+ col[0] = ((float)r) / 255.0f;
+ col[1] = ((float)g) / 255.0f;
+ col[2] = ((float)b) / 255.0f;
+ col[3] = ((float)a) / 255.0f;
+}
+
/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
{
@@ -2699,6 +2725,14 @@ void init_userdef_do_versions(void)
}
}
}
+
+ if (!USER_VERSION_ATLEAST(277, 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ if (btheme->tact.keyframe_scale_fac < 0.1f)
+ btheme->tact.keyframe_scale_fac = 1.0f;
+ }
+ }
/**
* Include next version bump.
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 1dfb1cddd2c..d4c49833c2c 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -287,8 +287,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
short a;
/* dvec */
- normalize_v3_v3(dvec, rv3d->persinv[2]);
- mul_v3_fl(dvec, offs);
+ normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
/* base correction */
copy_m3_m4(bmat, obedit->obmat);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 8868827a11f..e3e5863dc0e 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -153,8 +153,7 @@ static float edbm_rip_edge_side_measure(
ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat);
sub_v2_v2v2(vec, cent, mid);
- normalize_v2(vec);
- mul_v2_fl(vec, 0.01f);
+ normalize_v2_length(vec, 0.01f);
/* rather then adding to both verts, subtract from the mouse */
sub_v2_v2v2(fmval_tweak, fmval, vec);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 84ae35fae6e..5d5731a7e16 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2453,7 +2453,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit)
const bool is_walk_ok = (
(select_linked_delimit_test(e, delimit, &delimit_data) == false));
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
}
}
}
@@ -2496,7 +2496,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
if (delimit) {
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) {
+ if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
}
@@ -2552,7 +2552,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
BM_elem_flag_set(
e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG)));
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
}
}
else {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index efe179790da..3a7a8fb883b 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -49,6 +49,7 @@
#include "BKE_material.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_report.h"
#include "BKE_texture.h"
@@ -79,6 +80,8 @@
#include "mesh_intern.h" /* own include */
+#include "bmesh_tools.h"
+
#define USE_FACE_CREATE_SEL_EXTEND
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
@@ -2910,7 +2913,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
}
}
- BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
+ BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
}
@@ -2982,7 +2985,9 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
Object *obedit = base_old->object;
BMesh *bm_new;
- bm_new = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_new = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
@@ -3290,11 +3295,13 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
Object *ob = base_iter->object;
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
BMesh *bm_old = NULL;
int retval_iter = 0;
- bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_old = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
@@ -3975,6 +3982,196 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
join_triangle_props(ot);
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Decimate
+ *
+ * \note The function to decimate is intended for use as a modifier,
+ * while its handy allow access as a tool - this does cause access to be a little awkward
+ * (passing selection as weights for eg).
+ *
+ * \{ */
+
+static int edbm_decimate_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const float ratio = RNA_float_get(op->ptr, "ratio");
+ bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group");
+ const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor");
+ const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group");
+ const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry");
+ const float symmetry_eps = 0.00002f;
+ const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1;
+
+ /* nop */
+ if (ratio == 1.0f) {
+ return OPERATOR_FINISHED;
+ }
+
+ float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
+ {
+ const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ const int defbase_act = obedit->actdef - 1;
+
+ if (use_vertex_group && (cd_dvert_offset == -1)) {
+ BKE_report(op->reports, RPT_WARNING, "No active vertex group");
+ use_vertex_group = false;
+ }
+
+ BMIter iter;
+ BMVert *v;
+ int i;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ float weight = 0.0f;
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (use_vertex_group) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
+ weight = defvert_find_weight(dv, defbase_act);
+ if (invert_vertex_group) {
+ weight = 1.0 - weight;
+ }
+ }
+ else {
+ weight = 1.0f;
+ }
+ }
+
+ vweights[i] = weight;
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+ }
+
+ float ratio_adjust;
+
+ if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
+ ratio_adjust = ratio;
+ }
+ else {
+ /**
+ * Calculate a new ratio based on faces that could be remoevd during decimation.
+ * needed so 0..1 has a meaningful range when operating on the selection.
+ *
+ * This doesn't have to be totally accurate,
+ * but needs to be greater than the number of selected faces
+ */
+
+ int totface_basis = 0;
+ int totface_adjacent = 0;
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ /* count faces during decimation, ngons are triangulated */
+ const int f_len = f->len > 4 ? (f->len - 2) : 1;
+ totface_basis += f_len;
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
+ totface_adjacent += f_len;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ ratio_adjust = ratio;
+ ratio_adjust = 1.0f - ratio_adjust;
+ ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
+ ratio_adjust = 1.0f - ratio_adjust;
+ }
+
+ BM_mesh_decimate_collapse(
+ em->bm, ratio_adjust, vweights, vertex_group_factor, false,
+ symmetry_axis, symmetry_eps);
+
+ MEM_freeN(vweights);
+
+ {
+ short selectmode = em->selectmode;
+ if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
+ /* ensure we flush edges -> faces */
+ selectmode |= SCE_SELECT_EDGE;
+ }
+ EDBM_selectmode_flush_ex(em, selectmode);
+ }
+
+ EDBM_update_generic(em, true, true);
+
+ return OPERATOR_FINISHED;
+}
+
+
+static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return true;
+}
+
+
+static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout, *box, *row, *col;
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemR(box, &ptr, "use_vertex_group", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(box, false);
+ uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group"));
+ uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemR(box, &ptr, "use_symmetry", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, true);
+ uiLayoutSetActive(row, RNA_boolean_get(&ptr, "use_symmetry"));
+ uiItemR(row, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+}
+
+
+void MESH_OT_decimate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Decimate Geometry";
+ ot->idname = "MESH_OT_decimate";
+ ot->description = "Simplify geometry by collapsing edges";
+
+ /* api callbacks */
+ ot->exec = edbm_decimate_exec;
+ ot->check = edbm_decimate_check;
+ ot->ui = edbm_decimate_ui;
+ ot->poll = ED_operator_editmesh;
+
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Note, keep in sync with 'rna_def_modifier_decimate' */
+ RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
+
+ RNA_def_boolean(ot->srna, "use_vertex_group", false, "Vertex Group",
+ "Use active vertex group as an influence");
+ RNA_def_float(ot->srna, "vertex_group_factor", 1.0f, 0.0f, 1000.0f, "Weight",
+ "Vertex group strength", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "invert_vertex_group", false, "Invert",
+ "Invert vertex group influence");
+
+ RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry",
+ "Maintain symmetry on an axis");
+
+ RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry");
+}
+
+/** \} */
+
+
/* -------------------------------------------------------------------- */
/* Dissolve */
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 62656d75b9a..c9814d189a4 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -114,7 +114,7 @@ static struct {
TaskPool *task_pool;
#endif
-} um_arraystore = {NULL};
+} um_arraystore = {{NULL}};
static void um_arraystore_cd_compact(
struct CustomData *cdata, const size_t data_len,
@@ -563,7 +563,9 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
EDBM_mesh_free(em);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_bm_from_me(
bm, &um->me, (&(struct BMeshFromMeshParams){
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 99be37845ee..4fc61e0912e 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -354,7 +354,9 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
BKE_mesh_convert_mfaces_to_mpolys(me);
}
- bm = BKE_mesh_to_bmesh(me, ob, add_key_index);
+ bm = BKE_mesh_to_bmesh(
+ me, ob, add_key_index,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
if (me->edit_btmesh) {
/* this happens when switching shape keys */
@@ -399,10 +401,25 @@ void EDBM_mesh_load(Object *ob)
BKE_mesh_tessface_calc(me);
#endif
- /* free derived mesh. usually this would happen through depsgraph but there
+ /* Free derived mesh. usually this would happen through depsgraph but there
* are exceptions like file save that will not cause this, and we want to
- * avoid ending up with an invalid derived mesh then */
- BKE_object_free_derived_caches(ob);
+ * avoid ending up with an invalid derived mesh then.
+ *
+ * Do it for all objects which shares the same mesh datablock, since their
+ * derived meshes might also be referencing data which was just freed,
+ *
+ * Annoying enough, but currently seems most efficient way to avoid access
+ * of freed data on scene update, especially in cases when there are dependency
+ * cycles.
+ */
+ for (Object *other_object = G.main->object.first;
+ other_object != NULL;
+ other_object = other_object->id.next)
+ {
+ if (other_object->data == ob->data) {
+ BKE_object_free_derived_caches(other_object);
+ }
+ }
}
/**
@@ -1423,13 +1440,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
sub_v3_v3v3(dir2, origin, co2);
sub_v3_v3v3(dir3, origin, co3);
- normalize_v3(dir1);
- normalize_v3(dir2);
- normalize_v3(dir3);
-
- mul_v3_fl(dir1, epsilon);
- mul_v3_fl(dir2, epsilon);
- mul_v3_fl(dir3, epsilon);
+ normalize_v3_length(dir1, epsilon);
+ normalize_v3_length(dir2, epsilon);
+ normalize_v3_length(dir3, epsilon);
/* offset coordinates slightly along view vectors, to avoid
* hitting the faces that own the edge.*/
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index e0ddc017e93..772bb1bd308 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -511,7 +511,7 @@ static int layers_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data));
}
static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -759,7 +759,7 @@ static int mesh_customdata_mask_clear_poll(bContext *C)
return false;
}
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
CustomData *data = GET_CD_DATA(me, vdata);
if (CustomData_has_layer(data, CD_PAINT_MASK)) {
return true;
@@ -813,7 +813,7 @@ static int mesh_customdata_skin_state(bContext *C)
if (ob && ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
CustomData *data = GET_CD_DATA(me, vdata);
return CustomData_has_layer(data, CD_MVERT_SKIN);
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 08b4d1aee45..300b21a052d 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -216,6 +216,7 @@ void MESH_OT_fill_holes(struct wmOperatorType *ot);
void MESH_OT_beautify_fill(struct wmOperatorType *ot);
void MESH_OT_quads_convert_to_tris(struct wmOperatorType *ot);
void MESH_OT_tris_convert_to_quads(struct wmOperatorType *ot);
+void MESH_OT_decimate(struct wmOperatorType *ot);
void MESH_OT_dissolve_verts(struct wmOperatorType *ot);
void MESH_OT_dissolve_edges(struct wmOperatorType *ot);
void MESH_OT_dissolve_faces(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 2853ae3a84c..697a92f36d1 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -106,6 +106,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_beautify_fill);
WM_operatortype_append(MESH_OT_quads_convert_to_tris);
WM_operatortype_append(MESH_OT_tris_convert_to_quads);
+ WM_operatortype_append(MESH_OT_decimate);
WM_operatortype_append(MESH_OT_dissolve_verts);
WM_operatortype_append(MESH_OT_dissolve_edges);
WM_operatortype_append(MESH_OT_dissolve_faces);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 1b2d4b7c130..b26989113d4 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -172,7 +172,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
*/
if (key) {
/* make a duplicate copy that will only be used here... (must remember to free it!) */
- nkey = BKE_key_copy(key);
+ nkey = BKE_key_copy(bmain, key);
/* for all keys in old block, clear data-arrays */
for (kb = key->block.first; kb; kb = kb->next) {
@@ -540,7 +540,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (matmap) MEM_freeN(matmap);
/* other mesh users */
- test_object_materials(bmain, (ID *)me);
+ test_all_objects_materials(bmain, (ID *)me);
/* free temp copy of destination shapekeys (if applicable) */
if (nkey) {
@@ -564,21 +564,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
-
DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag
-#if 0
- ED_object_editmode_enter(C, EM_WAITCURSOR);
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
-#else
- /* toggle editmode using lower level functions so this can be called from python */
- EDBM_mesh_make(scene->toolsettings, ob, false);
- EDBM_mesh_load(ob);
- EDBM_mesh_free(me->edit_btmesh);
- MEM_freeN(me->edit_btmesh);
- me->edit_btmesh = NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
-#endif
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 9a38a292656..15c1a195db5 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -73,6 +73,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -1107,11 +1108,18 @@ static void object_delete_check_glsl_update(Object *ob)
/* note: now unlinks constraints as well */
void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
{
- DAG_id_type_tag(bmain, ID_OB);
+ if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ /* We cannot delete indirectly used object... */
+ printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
+ base->object->id.name + 2);
+ return;
+ }
+
BKE_scene_base_unlink(scene, base);
object_delete_check_glsl_update(base->object);
BKE_libblock_free_us(bmain, base->object);
MEM_freeN(base);
+ DAG_id_type_tag(bmain, ID_OB);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1128,6 +1136,19 @@ static int object_delete_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
+ const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ /* Can this case ever happen? */
+ BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ continue;
+ }
+ else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ continue;
+ }
+
/* deselect object -- it could be used in other scenes */
base->object->flag &= ~SELECT;
@@ -1140,9 +1161,15 @@ static int object_delete_exec(bContext *C, wmOperator *op)
Base *base_other;
for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) {
- if (scene_iter != scene && !(scene_iter->id.lib)) {
+ if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) {
base_other = BKE_scene_base_find(scene_iter, base->object);
if (base_other) {
+ if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene_iter->id.name + 2);
+ break;
+ }
ED_base_object_free_and_unlink(bmain, scene_iter, base_other);
}
}
@@ -1271,7 +1298,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
for (dob = lb->first; dob; dob = dob->next) {
Base *basen;
- Object *ob = BKE_object_copy(dob->ob);
+ Object *ob = BKE_object_copy(bmain, dob->ob);
/* font duplis can have a totcol without material, we get them from parent
* should be implemented better...
@@ -1487,11 +1514,12 @@ static int convert_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- return (!scene->id.lib && obact && scene->obedit != obact && (obact->flag & SELECT) && !(obact->id.lib));
+ return (!ID_IS_LINKED_DATABLOCK(scene) && obact && scene->obedit != obact &&
+ (obact->flag & SELECT) && !ID_IS_LINKED_DATABLOCK(obact));
}
/* Helper for convert_exec */
-static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob)
+static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob)
{
Object *obn;
Base *basen;
@@ -1500,7 +1528,7 @@ static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob)
ob = base->object;
}
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
basen = MEM_mallocN(sizeof(Base), "duplibase");
@@ -1580,7 +1608,7 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1588,7 +1616,7 @@ static int convert_exec(bContext *C, wmOperator *op)
id_us_min(&me->id);
/* make a new copy of the mesh */
- newob->data = BKE_mesh_copy(me);
+ newob->data = BKE_mesh_copy(bmain, me);
}
else {
newob = ob;
@@ -1605,7 +1633,7 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1613,7 +1641,7 @@ static int convert_exec(bContext *C, wmOperator *op)
id_us_min(&me->id);
/* make a new copy of the mesh */
- newob->data = BKE_mesh_copy(me);
+ newob->data = BKE_mesh_copy(bmain, me);
}
else {
newob = ob;
@@ -1637,14 +1665,14 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
- newob->data = BKE_curve_copy(ob->data);
+ newob->data = BKE_curve_copy(bmain, ob->data);
}
else {
newob = ob;
@@ -1708,14 +1736,14 @@ static int convert_exec(bContext *C, wmOperator *op)
if (target == OB_MESH) {
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
- newob->data = BKE_curve_copy(ob->data);
+ newob->data = BKE_curve_copy(bmain, ob->data);
}
else {
newob = ob;
@@ -1743,7 +1771,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!(baseob->flag & OB_DONE)) {
baseob->flag |= OB_DONE;
- basen = duplibase_for_convert(scene, base, baseob);
+ basen = duplibase_for_convert(bmain, scene, base, baseob);
newob = basen->object;
mb = newob->data;
@@ -1881,7 +1909,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
; /* nothing? */
}
else {
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
basen = MEM_mallocN(sizeof(Base), "duplibase");
@@ -1912,7 +1940,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (id) {
ID_NEW_US(obn->mat[a])
else
- obn->mat[a] = BKE_material_copy(obn->mat[a]);
+ obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]);
id_us_min(id);
if (dupflag & USER_DUP_ACT) {
@@ -1930,7 +1958,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_MESH) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_mesh_copy(obn->data);
+ obn->data = BKE_mesh_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1940,7 +1968,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_CURVE) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1950,7 +1978,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_SURF) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1960,7 +1988,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_FONT) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1970,7 +1998,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_MBALL) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_mball_copy(obn->data);
+ obn->data = BKE_mball_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1980,7 +2008,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_LAMP) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_lamp_copy(obn->data);
+ obn->data = BKE_lamp_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1993,7 +2021,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ARM) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_armature_copy(obn->data);
+ obn->data = BKE_armature_copy(bmain, obn->data);
BKE_pose_rebuild(obn, obn->data);
didit = 1;
}
@@ -2004,7 +2032,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_lattice_copy(obn->data);
+ obn->data = BKE_lattice_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2014,7 +2042,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_camera_copy(obn->data);
+ obn->data = BKE_camera_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2024,7 +2052,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_speaker_copy(obn->data);
+ obn->data = BKE_speaker_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2063,7 +2091,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (id) {
ID_NEW_US((*matarar)[a])
else
- (*matarar)[a] = BKE_material_copy((*matarar)[a]);
+ (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]);
id_us_min(id);
}
}
@@ -2260,7 +2288,7 @@ static int join_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
return ED_operator_screenactive(C);
@@ -2313,7 +2341,7 @@ static int join_shapes_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
/* only meshes supported at the moment */
if (ob->type == OB_MESH)
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 9c2806f6f5a..db8a4c1960f 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -584,7 +584,7 @@ static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
return 0;
}
- if (ob->id.lib || (ptr.id.data && ((ID *)ptr.id.data)->lib)) {
+ if (ID_IS_LINKED_DATABLOCK(ob) || (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data))) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
return 0;
}
@@ -1651,7 +1651,7 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob
break;
}
else if (((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
+ ((!only_mesh) || (ob->type == OB_MESH)))
{
/* set target */
*tar_ob = ob;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 47ee6752e51..acee69daab7 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -300,7 +300,7 @@ static void data_transfer_exec_preprocess_objects(
}
me = ob->data;
- if (me->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(me)) {
/* Do not transfer to linked data, not supported. */
BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified",
ob->id.name + 2, me->id.name + 2);
@@ -330,7 +330,7 @@ static bool data_transfer_exec_is_object_valid(
me->id.tag &= ~LIB_TAG_DOIT;
return true;
}
- else if (me->id.lib == NULL) {
+ else if (!ID_IS_LINKED_DATABLOCK(me)) {
/* Do not transfer apply operation more than once. */
/* XXX This is not nice regarding vgroups, which are half-Object data... :/ */
BKE_reportf(op->reports, RPT_WARNING,
@@ -387,7 +387,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- if (reverse_transfer && ((ID *)(ob_src->data))->lib) {
+ if (reverse_transfer && ID_IS_LINKED_DATABLOCK(ob_src->data)) {
/* Do not transfer to linked data, not supported. */
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index fbbb9f9e253..e467dbd05eb 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -456,7 +456,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
View3D *v3d = NULL;
bool ok = false;
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
if (sa && sa->spacetype == SPACE_VIEW3D)
v3d = sa->spacedata.first;
@@ -525,7 +525,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
* BKE_object_obdata_is_libdata that prevent the bugfix #6614, so
* i add this little hack here.
*/
- if (arm->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(arm)) {
error_libdata();
return;
}
@@ -607,7 +607,7 @@ static int editmode_toggle_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
/* covers proxies too */
- if (ELEM(NULL, ob, ob->data) || ((ID *)ob->data)->lib)
+ if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
/* if hidden but in edit mode, we still display */
@@ -834,7 +834,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
Nurb *nu;
bool do_depgraph_update = false;
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
if (!(ob = OBACT)) return;
@@ -1422,7 +1422,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
{
data = ob->data;
- if (data && data->lib) {
+ if (data && ID_IS_LINKED_DATABLOCK(data)) {
linked_data = true;
continue;
}
@@ -1505,7 +1505,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
int a, b, done;
if (scene->obedit) return; // XXX get from context
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
for (base = FIRSTBASE; base; base = base->next) {
if (TESTBASELIB(v3d, base)) {
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 2b87a890f0f..bcdd170c53c 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -528,7 +528,7 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_libblock_unlink(bmain, group, false);
+ BKE_libblock_unlink(bmain, group, false, false);
BKE_libblock_free(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index efdb9263d7b..9175bd69a28 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -673,9 +673,9 @@ int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
- if (ptr.id.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 9e5eeedd449..4837ca50105 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -364,9 +364,21 @@ void ED_keymap_object(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "OBJECT_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "OBJECT_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+
WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 7a55418b082..55eb30ac2de 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -290,17 +290,17 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *ob = ED_object_active_context(C);
/* sanity checks */
- if (!scene || scene->id.lib || !ob)
+ if (!scene || ID_IS_LINKED_DATABLOCK(scene) || !ob)
return OPERATOR_CANCELLED;
/* Get object to work on - use a menu if we need to... */
- if (ob->dup_group && ob->dup_group->id.lib) {
+ if (ob->dup_group && ID_IS_LINKED_DATABLOCK(ob->dup_group)) {
/* gives menu with list of objects in group */
/* proxy_group_objects_menu(C, op, ob, ob->dup_group); */
WM_enum_search_invoke(C, op, event);
return OPERATOR_CANCELLED;
}
- else if (ob->id.lib) {
+ else if (ID_IS_LINKED_DATABLOCK(ob)) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = UI_popup_menu_layout(pup);
@@ -1465,7 +1465,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (scene_to->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(scene_to)) {
BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene");
return OPERATOR_CANCELLED;
}
@@ -1563,7 +1563,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
ob_dst->data = obdata_id;
/* if amount of material indices changed: */
- test_object_materials(bmain, ob_dst->data);
+ test_object_materials(ob_dst, ob_dst->data);
DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
@@ -1578,7 +1578,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
case MAKE_LINKS_ANIMDATA:
BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
- if (obdata_id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata_id)) {
is_lib = true;
break;
}
@@ -1620,7 +1620,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
Curve *cu_src = ob_src->data;
Curve *cu_dst = ob_dst->data;
- if (obdata_id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata_id)) {
is_lib = true;
break;
}
@@ -1748,9 +1748,9 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
ob = base->object;
if ((base->flag & flag) == flag) {
- if (ob->id.lib == NULL && ob->id.us > 1) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
/* base gets copy of object */
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
base->object = obn;
if (copy_groups) {
@@ -1783,7 +1783,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
if (all_duplicated) {
- groupn = BKE_group_copy(group);
+ groupn = BKE_group_copy(bmain, group);
for (go = groupn->gobject.first; go; go = go->next)
go->ob = (Object *)go->ob->id.newid;
@@ -1820,21 +1820,21 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
}
-static void new_id_matar(Material **matar, const int totcol)
+static void new_id_matar(Main *bmain, Material **matar, const int totcol)
{
ID *id;
int a;
for (a = 0; a < totcol; a++) {
id = (ID *)matar[a];
- if (id && id->lib == NULL) {
+ if (id && !ID_IS_LINKED_DATABLOCK(id)) {
if (id->newid) {
matar[a] = (Material *)id->newid;
id_us_plus(id->newid);
id_us_min(id);
}
else if (id->us > 1) {
- matar[a] = BKE_material_copy(matar[a]);
+ matar[a] = BKE_material_copy(bmain, matar[a]);
id_us_min(id);
id->newid = (ID *)matar[a];
}
@@ -1856,15 +1856,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (base->flag & flag) == flag) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (base->flag & flag) == flag) {
id = ob->data;
- if (id && id->us > 1 && id->lib == NULL) {
+ if (id && id->us > 1 && !ID_IS_LINKED_DATABLOCK(id)) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
switch (ob->type) {
case OB_LAMP:
- ob->data = la = BKE_lamp_copy(ob->data);
+ ob->data = la = BKE_lamp_copy(bmain, ob->data);
for (a = 0; a < MAX_MTEX; a++) {
if (la->mtex[a]) {
ID_NEW(la->mtex[a]->object);
@@ -1872,37 +1872,37 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
}
break;
case OB_CAMERA:
- ob->data = BKE_camera_copy(ob->data);
+ ob->data = BKE_camera_copy(bmain, ob->data);
break;
case OB_MESH:
- ob->data = me = BKE_mesh_copy(ob->data);
+ ob->data = me = BKE_mesh_copy(bmain, ob->data);
if (me->key)
BKE_animdata_copy_id_action((ID *)me->key);
break;
case OB_MBALL:
- ob->data = BKE_mball_copy(ob->data);
+ ob->data = BKE_mball_copy(bmain, ob->data);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- ob->data = cu = BKE_curve_copy(ob->data);
+ ob->data = cu = BKE_curve_copy(bmain, ob->data);
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
BKE_animdata_copy_id_action((ID *)cu->key);
break;
case OB_LATTICE:
- ob->data = lat = BKE_lattice_copy(ob->data);
+ ob->data = lat = BKE_lattice_copy(bmain, ob->data);
if (lat->key)
BKE_animdata_copy_id_action((ID *)lat->key);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->data = BKE_armature_copy(ob->data);
+ ob->data = BKE_armature_copy(bmain, ob->data);
BKE_pose_rebuild(ob, ob->data);
break;
case OB_SPEAKER:
- ob->data = BKE_speaker_copy(ob->data);
+ ob->data = BKE_speaker_copy(bmain, ob->data);
break;
default:
if (G.debug & G_DEBUG)
@@ -1937,14 +1937,14 @@ static void single_object_action_users(Scene *scene, const int flag)
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
BKE_animdata_copy_id_action(&ob->id);
}
}
}
-static void single_mat_users(Scene *scene, const int flag, const bool do_textures)
+static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures)
{
Object *ob;
Base *base;
@@ -1954,14 +1954,14 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
/* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
- man = BKE_material_copy(ma);
+ man = BKE_material_copy(bmain, ma);
BKE_animdata_copy_id_action(&man->id);
man->id.us = 0;
@@ -1972,7 +1972,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) {
if (tex->id.us > 1) {
id_us_min(&tex->id);
- tex = BKE_texture_copy(tex);
+ tex = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
}
@@ -1986,7 +1986,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
}
}
-static void do_single_tex_user(Tex **from)
+static void do_single_tex_user(Main *bmain, Tex **from)
{
Tex *tex, *texn;
@@ -1999,7 +1999,7 @@ static void do_single_tex_user(Tex **from)
id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
- texn = BKE_texture_copy(tex);
+ texn = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
id_us_min(&tex->id);
@@ -2019,7 +2019,7 @@ static void single_tex_users_expand(Main *bmain)
if (ma->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (ma->mtex[b] && ma->mtex[b]->tex) {
- do_single_tex_user(&(ma->mtex[b]->tex));
+ do_single_tex_user(bmain, &(ma->mtex[b]->tex));
}
}
}
@@ -2029,7 +2029,7 @@ static void single_tex_users_expand(Main *bmain)
if (la->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (la->mtex[b] && la->mtex[b]->tex) {
- do_single_tex_user(&(la->mtex[b]->tex));
+ do_single_tex_user(bmain, &(la->mtex[b]->tex));
}
}
}
@@ -2039,7 +2039,7 @@ static void single_tex_users_expand(Main *bmain)
if (wo->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (wo->mtex[b] && wo->mtex[b]->tex) {
- do_single_tex_user(&(wo->mtex[b]->tex));
+ do_single_tex_user(bmain, &(wo->mtex[b]->tex));
}
}
}
@@ -2058,19 +2058,19 @@ static void single_mat_users_expand(Main *bmain)
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->id.tag & LIB_TAG_NEW)
- new_id_matar(ob->mat, ob->totcol);
+ new_id_matar(bmain, ob->mat, ob->totcol);
for (me = bmain->mesh.first; me; me = me->id.next)
if (me->id.tag & LIB_TAG_NEW)
- new_id_matar(me->mat, me->totcol);
+ new_id_matar(bmain, me->mat, me->totcol);
for (cu = bmain->curve.first; cu; cu = cu->id.next)
if (cu->id.tag & LIB_TAG_NEW)
- new_id_matar(cu->mat, cu->totcol);
+ new_id_matar(bmain, cu->mat, cu->totcol);
for (mb = bmain->mball.first; mb; mb = mb->id.next)
if (mb->id.tag & LIB_TAG_NEW)
- new_id_matar(mb->mat, mb->totcol);
+ new_id_matar(bmain, mb->mat, mb->totcol);
/* material imats */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
@@ -2103,11 +2103,11 @@ static void make_local_makelocalmaterial(Material *ma)
AnimData *adt;
int b;
- id_make_local(&ma->id, false);
+ id_make_local(G.main, &ma->id, false);
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(&ma->mtex[b]->tex->id, false);
+ id_make_local(G.main, &ma->mtex[b]->tex->id, false);
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2183,7 +2183,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
bool changed = false;
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->id.lib && (ob->id.us == 0)) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && (ob->id.us == 0)) {
Base *base;
id_us_plus(&ob->id);
@@ -2235,7 +2235,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
if (ob->id.lib)
- id_make_local(&ob->id, false);
+ id_make_local(bmain, &ob->id, false);
}
CTX_DATA_END;
@@ -2257,7 +2257,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id = ob->data;
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(id, false);
+ id_make_local(bmain, id, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
@@ -2289,7 +2289,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
for (b = 0; b < MAX_MTEX; b++)
if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(&la->mtex[b]->tex->id, false);
+ id_make_local(bmain, &la->mtex[b]->tex->id, false);
}
else {
for (a = 0; a < ob->totcol; a++) {
@@ -2371,7 +2371,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
}
if (RNA_boolean_get(op->ptr, "material")) {
- single_mat_users(scene, flag, RNA_boolean_get(op->ptr, "texture"));
+ single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture"));
}
#if 0 /* can't do this separate from materials */
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 39bd34456be..e04114761e4 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -225,7 +225,7 @@ static int shape_key_mode_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT);
}
static int shape_key_mode_exists_poll(bContext *C)
@@ -234,7 +234,7 @@ static int shape_key_mode_exists_poll(bContext *C)
ID *data = (ob) ? ob->data : NULL;
/* same as shape_key_mode_poll */
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT) &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT) &&
/* check a keyblock exists */
(BKE_keyblock_from_object(ob) != NULL);
}
@@ -246,14 +246,15 @@ static int shape_key_move_poll(bContext *C)
ID *data = (ob) ? ob->data : NULL;
Key *key = BKE_key_from_object(ob);
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) &&
+ ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
}
static int shape_key_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data));
}
static int shape_key_add_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index d2bbb73b597..4d7d7df0d2f 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -76,60 +76,87 @@
/*************************** Clear Transformation ****************************/
/* clear location of object */
-static void object_clear_loc(Object *ob)
+static void object_clear_loc(Object *ob, const bool clear_delta)
{
/* clear location if not locked */
- if ((ob->protectflag & OB_LOCK_LOCX) == 0)
- ob->loc[0] = ob->dloc[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_LOCY) == 0)
- ob->loc[1] = ob->dloc[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
- ob->loc[2] = ob->dloc[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] = 0.0f;
+ if (clear_delta) ob->dloc[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] = 0.0f;
+ if (clear_delta) ob->dloc[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] = 0.0f;
+ if (clear_delta) ob->dloc[2] = 0.0f;
+ }
}
/* clear rotation of object */
-static void object_clear_rot(Object *ob)
+static void object_clear_rot(Object *ob, const bool clear_delta)
{
/* clear rotations that aren't locked */
if (ob->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
if (ob->protectflag & OB_LOCK_ROT4D) {
/* perform clamping on a component by component basis */
if (ob->rotmode == ROT_MODE_AXISANGLE) {
- if ((ob->protectflag & OB_LOCK_ROTW) == 0)
- ob->rotAngle = ob->drotAngle = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->rotAxis[0] = ob->drotAxis[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->rotAxis[1] = ob->drotAxis[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->rotAxis[2] = ob->drotAxis[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_ROTW) == 0) {
+ ob->rotAngle = 0.0f;
+ if (clear_delta) ob->drotAngle = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->rotAxis[0] = 0.0f;
+ if (clear_delta) ob->drotAxis[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->rotAxis[1] = 0.0f;
+ if (clear_delta) ob->drotAxis[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->rotAxis[2] = 0.0f;
+ if (clear_delta) ob->drotAxis[2] = 0.0f;
+ }
/* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
ob->rotAxis[1] = 1.0f;
- if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
+ if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]) && clear_delta)
ob->drotAxis[1] = 1.0f;
}
else if (ob->rotmode == ROT_MODE_QUAT) {
- if ((ob->protectflag & OB_LOCK_ROTW) == 0)
- ob->quat[0] = ob->dquat[0] = 1.0f;
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->quat[1] = ob->dquat[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->quat[2] = ob->dquat[2] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->quat[3] = ob->dquat[3] = 0.0f;
-
+ if ((ob->protectflag & OB_LOCK_ROTW) == 0) {
+ ob->quat[0] = 1.0f;
+ if (clear_delta) ob->dquat[0] = 1.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->quat[1] = 0.0f;
+ if (clear_delta) ob->dquat[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->quat[2] = 0.0f;
+ if (clear_delta) ob->dquat[2] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->quat[3] = 0.0f;
+ if (clear_delta) ob->dquat[3] = 0.0f;
+ }
/* TODO: does this quat need normalizing now? */
}
else {
/* the flag may have been set for the other modes, so just ignore the extra flag... */
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->rot[0] = ob->drot[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->rot[1] = ob->drot[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->rot[2] = ob->drot[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->rot[0] = 0.0f;
+ if (clear_delta) ob->drot[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->rot[1] = 0.0f;
+ if (clear_delta) ob->drot[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->rot[2] = 0.0f;
+ if (clear_delta) ob->drot[2] = 0.0f;
+ }
}
}
else {
@@ -175,34 +202,34 @@ static void object_clear_rot(Object *ob)
else {
if (ob->rotmode == ROT_MODE_QUAT) {
unit_qt(ob->quat);
- unit_qt(ob->dquat);
+ if (clear_delta) unit_qt(ob->dquat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
unit_axis_angle(ob->rotAxis, &ob->rotAngle);
- unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+ if (clear_delta) unit_axis_angle(ob->drotAxis, &ob->drotAngle);
}
else {
zero_v3(ob->rot);
- zero_v3(ob->drot);
+ if (clear_delta) zero_v3(ob->drot);
}
}
}
/* clear scale of object */
-static void object_clear_scale(Object *ob)
+static void object_clear_scale(Object *ob, const bool clear_delta)
{
/* clear scale factors which are not locked */
if ((ob->protectflag & OB_LOCK_SCALEX) == 0) {
- ob->dscale[0] = 1.0f;
ob->size[0] = 1.0f;
+ if (clear_delta) ob->dscale[0] = 1.0f;
}
if ((ob->protectflag & OB_LOCK_SCALEY) == 0) {
- ob->dscale[1] = 1.0f;
ob->size[1] = 1.0f;
+ if (clear_delta) ob->dscale[1] = 1.0f;
}
if ((ob->protectflag & OB_LOCK_SCALEZ) == 0) {
- ob->dscale[2] = 1.0f;
ob->size[2] = 1.0f;
+ if (clear_delta) ob->dscale[2] = 1.0f;
}
}
@@ -210,10 +237,12 @@ static void object_clear_scale(Object *ob)
/* generic exec for clear-transform operators */
static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
- void (*clear_func)(Object *), const char default_ksName[])
+ void (*clear_func)(Object *, const bool),
+ const char default_ksName[])
{
Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
+ const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta");
/* sanity checks */
if (ELEM(NULL, clear_func, default_ksName)) {
@@ -231,10 +260,10 @@ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
{
if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
/* run provided clearing function */
- clear_func(ob);
-
+ clear_func(ob, clear_delta);
+
ED_autokeyframe_object(C, scene, ob, ks);
-
+
/* tag for updates */
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -268,6 +297,11 @@ void OBJECT_OT_location_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta location in addition to clearing the normal location transform");
}
static int object_rotation_clear_exec(bContext *C, wmOperator *op)
@@ -288,6 +322,10 @@ void OBJECT_OT_rotation_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta rotation in addition to clearing the normal rotation transform");
}
static int object_scale_clear_exec(bContext *C, wmOperator *op)
@@ -308,6 +346,10 @@ void OBJECT_OT_scale_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta scale in addition to clearing the normal scale transform");
}
/* --------------- */
@@ -391,7 +433,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
changed = false;
}
- if (obdata->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata)) {
BKE_reportf(reports, RPT_ERROR,
"Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
@@ -792,7 +834,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (ob->data == NULL) {
/* special support for dupligroups */
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) {
- if (ob->dup_group->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob->dup_group)) {
tot_lib_error++;
}
else {
@@ -817,7 +859,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
}
- else if (((ID *)ob->data)->lib) {
+ else if (ID_IS_LINKED_DATABLOCK(ob->data)) {
tot_lib_error++;
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 414cc476be5..6e8aaebcccc 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -2447,8 +2447,8 @@ static int vertex_group_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib &&
- data && !data->lib &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) &&
+ data && !ID_IS_LINKED_DATABLOCK(data) &&
OB_TYPE_SUPPORT_VGROUP(ob->type) &&
ob->defbase.first);
}
@@ -2457,7 +2457,8 @@ static int vertex_group_supported_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) &&
+ data && !ID_IS_LINKED_DATABLOCK(data));
}
static int vertex_group_mesh_poll(bContext *C)
@@ -2465,8 +2466,8 @@ static int vertex_group_mesh_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib &&
- data && !data->lib &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) &&
+ data && !ID_IS_LINKED_DATABLOCK(data) &&
ob->type == OB_MESH &&
ob->defbase.first);
}
@@ -2475,7 +2476,7 @@ static int UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data));
}
@@ -2484,7 +2485,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
return BKE_object_is_in_editmode_vgroup(ob);
@@ -2496,7 +2497,7 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return false;
if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) {
@@ -2536,7 +2537,7 @@ static int vertex_group_vert_select_unlocked_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
if (!(BKE_object_is_in_editmode_vgroup(ob) ||
@@ -2559,7 +2560,7 @@ static int vertex_group_vert_select_mesh_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
/* only difference to #vertex_group_vert_select_poll */
@@ -2748,7 +2749,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- if (!ob || ob->id.lib)
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob))
return OPERATOR_CANCELLED;
vgroup_select_verts(ob, 1);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 132c3fa5438..76d0143e898 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -864,7 +864,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
/* T32865 - we need to unlink the texture copies, unlike for materials */
- BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true);
+ BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL, true);
BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
@@ -881,7 +881,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied lamp */
BLI_remlink(&pr_main->lamp, sp->lampcopy);
- BKE_libblock_relink_ex(sp->lampcopy, NULL, NULL, true);
+ BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL, true);
BKE_lamp_free(sp->lampcopy);
properties = IDP_GetProperties((ID *)sp->lampcopy, false);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 5d1d26a411f..bd5fd6b060a 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -463,7 +463,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy material */
if (ma) {
- ma = BKE_material_copy(ma);
+ ma = BKE_material_copy(bmain, ma);
}
else {
ma = BKE_material_add(bmain, DATA_("Material"));
@@ -517,7 +517,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy texture */
if (tex) {
- tex = BKE_texture_copy(tex);
+ tex = BKE_texture_copy(bmain, tex);
}
else {
tex = BKE_texture_add(bmain, DATA_("Texture"));
@@ -575,7 +575,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
- wo = BKE_world_copy(wo);
+ wo = BKE_world_copy(bmain, wo);
}
else {
wo = add_world(bmain, DATA_("World"));
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 0c0a6c93b3e..6dbb5db53d0 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -168,7 +168,7 @@ int ED_operator_screen_mainwinactive(bContext *C)
int ED_operator_scene_editable(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- if (scene && scene->id.lib == NULL)
+ if (scene && !ID_IS_LINKED_DATABLOCK(scene))
return 1;
return 0;
}
@@ -178,7 +178,7 @@ int ED_operator_objectmode(bContext *C)
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- if (scene == NULL || scene->id.lib)
+ if (scene == NULL || ID_IS_LINKED_DATABLOCK(scene))
return 0;
if (CTX_data_edit_object(C))
return 0;
@@ -279,7 +279,7 @@ int ED_operator_node_editable(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
- if (snode && snode->edittree && snode->edittree->id.lib == NULL)
+ if (snode && snode->edittree && !ID_IS_LINKED_DATABLOCK(snode->edittree))
return 1;
return 0;
@@ -341,20 +341,20 @@ int ED_operator_object_active(bContext *C)
int ED_operator_object_active_editable(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob));
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob));
}
int ED_operator_object_active_editable_mesh(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) &&
- (ob->type == OB_MESH) && !(((ID *)ob->data)->lib));
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) &&
+ (ob->type == OB_MESH) && !ID_IS_LINKED_DATABLOCK(ob->data));
}
int ED_operator_object_active_editable_font(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) &&
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) &&
(ob->type == OB_FONT));
}
@@ -3955,7 +3955,7 @@ static int scene_new_exec(bContext *C, wmOperator *op)
newscene = BKE_scene_add(bmain, DATA_("Scene"));
}
else { /* different kinds of copying */
- newscene = BKE_scene_copy(scene, type);
+ newscene = BKE_scene_copy(bmain, scene, type);
/* these can't be handled in blenkernel currently, so do them here */
if (type == SCE_COPY_LINK_DATA) {
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index eba9448aa40..53c11e2a6a9 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1016,7 +1016,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
translation[1] = y;
outline_alpha = 0.5;
outline_col = brush->add_col;
- final_radius = (BKE_brush_size_get(scene, brush) * zoomx) / U.pixelsize;
+ final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 689b89e7b69..bf344e1f721 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -1342,7 +1342,7 @@ static int texture_paint_toggle_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH)
return 0;
- if (!ob->data || ((ID *)ob->data)->lib)
+ if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
if (CTX_data_edit_object(C))
return 0;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 827f83aa425..6ed969cb270 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -5858,7 +5858,9 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
Mesh *me = ob->data;
bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BMesh *bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index bf923415f01..f88b64129e7 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -69,7 +69,7 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
PaintMode mode = BKE_paintmode_get_active_from_context(C);
if (br)
- br = BKE_brush_copy(br);
+ br = BKE_brush_copy(bmain, br);
else
br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode));
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 5a6e0fe30ea..e874a969963 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -246,7 +246,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
{
Mesh *me;
- if ((ob->id.lib) ||
+ if (ID_IS_LINKED_DATABLOCK(ob) ||
((me = BKE_mesh_from_object(ob)) == NULL) ||
(me->totpoly == 0) ||
(me->edit_btmesh))
@@ -1840,7 +1840,7 @@ static int paint_poll_test(bContext *C)
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH)
return 0;
- if (!ob->data || ((ID *)ob->data)->lib)
+ if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
if (CTX_data_edit_object(C))
return 0;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c173156de3a..cc7531b9783 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5001,7 +5001,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BKE_mesh_mselect_clear(me);
/* Create triangles-only BMesh */
- ss->bm = BM_mesh_create(&allocsize);
+ ss->bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_mesh_bm_from_me(
ss->bm, me, (&(struct BMeshFromMeshParams){
@@ -5011,7 +5013,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
/* make sure the data for existing faces are initialized */
- BM_mesh_normals_update(ss->bm);
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
/* Enable dynamic topology */
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
@@ -5088,6 +5092,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ WM_cursor_wait(1);
+
if (ss->bm) {
sculpt_undo_push_begin("Dynamic topology disable");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
@@ -5100,16 +5106,24 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
}
sculpt_undo_push_end(C);
+ WM_cursor_wait(0);
+
return OPERATOR_FINISHED;
}
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
-static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers)
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
{
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
uiLayout *layout = UI_popup_menu_layout(pup);
- if (vdata) {
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
const char *msg_error = TIP_("Vertex Data Detected!");
const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
uiItemL(layout, msg_error, ICON_INFO);
@@ -5117,7 +5131,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
uiItemS(layout);
}
- if (modifiers) {
+ if (flag & DYNTOPO_WARN_MODIFIER) {
const char *msg_error = TIP_("Generative Modifiers Detected!");
const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode");
@@ -5133,33 +5147,35 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
return OPERATOR_INTERFACE;
}
-
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C)
{
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- int i;
- bool vdata = false;
- bool modifiers = false;
-
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
- (CustomData_has_layer(&me->vdata, i) ||
- CustomData_has_layer(&me->edata, i) ||
- CustomData_has_layer(&me->ldata, i)))
- {
- vdata = true;
- break;
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = 0;
+
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
+
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
}
}
+ }
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
@@ -5167,14 +5183,26 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
- modifiers = true;
+ flag |= DYNTOPO_WARN_MODIFIER;
break;
}
}
+ }
- if (vdata || modifiers) {
+ return flag;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->bm) {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+
+ if (flag) {
/* The mesh has customdata that will be lost, let the user confirm this is OK */
- return dyntopo_warning_popup(C, op->type, vdata, modifiers);
+ return dyntopo_warning_popup(C, op->type, flag);
}
}
@@ -5249,6 +5277,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
BM_log_before_all_removed(ss->bm, ss->bm_log);
+ BM_mesh_toolflags_set(ss->bm, true);
+
/* Symmetrize and re-triangulate */
BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
"symmetrize input=%avef direction=%i dist=%f",
@@ -5258,6 +5288,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
/* bisect operator flags edges (keep tags clean for edge queue) */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_toolflags_set(ss->bm, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end(C);
@@ -5327,6 +5359,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
* mode to ensure the undo stack stays in a consistent
* state */
sculpt_dynamic_topology_toggle_exec(C, NULL);
+
+ /* store so we know to re-enable when entering sculpt mode */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
}
/* Leave sculptmode */
@@ -5340,12 +5375,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Enter sculptmode */
ob->mode |= mode_flag;
- /* Remove dynamic-topology flag; this will be enabled if the
- * file was saved with dynamic topology on, but we don't
- * automatically re-enter dynamic-topology mode when loading a
- * file. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
if (flush_recalc)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -5399,6 +5428,52 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (message_unsupported == NULL) {
+ /* undo push is needed to prevent memory leak */
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable(C);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ }
+ else {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Dynamic Topology found: %s, disabled",
+ message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
}
if (ob->derivedFinal) /* VBO no longer valid */
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index ceefda99002..44bd872d107 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -366,7 +366,9 @@ static void sculpt_undo_bmesh_enable(Object *ob,
sculpt_pbvh_clear(ob);
/* Create empty BMesh and enable logging */
- ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ ss->bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index a3be7791f9a..6755a6316cc 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -121,7 +121,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
*/
if (oldact && GS(oldact->id.name) == ID_AC) {
/* make a copy of the existing action */
- action = BKE_action_copy(oldact);
+ action = BKE_action_copy(CTX_data_main(C), oldact);
}
else {
/* just make a new (empty) action */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 10748c2fe15..9fc96e06299 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -81,7 +81,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
+ height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
if (height > BLI_rcti_size_y(&v2d->mask)) {
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
@@ -95,11 +95,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
{ /* first pass: just the standard GL-drawing for backdrop + text */
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
- float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -110,7 +110,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
}
@@ -118,11 +118,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
- float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -133,7 +133,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
@@ -195,19 +195,19 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
+ height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin = (float)(-height);
/* first backdrop strips */
- y = (float)(-ACHANNEL_HEIGHT);
+ y = (float)(-ACHANNEL_HEIGHT(ac));
glEnable(GL_BLEND);
for (ale = anim_data.first; ale; ale = ale->next) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -260,39 +260,39 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
/* draw region twice: firstly backdrop, then the current range */
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
if (ac->datatype == ANIMCONT_ACTION)
- glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF, act_end, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
/* frames less than one get less saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_MASK) {
/* TODO --- this is a copy of gpencil */
/* frames less than one get less saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
}
}
/* Increment the step */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
glDisable(GL_BLEND);
@@ -301,11 +301,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
* This is to try to optimize this for heavier data sets
* 2) Keyframes which are out of view horizontally are disregarded
*/
- y = (float)(-ACHANNEL_HEIGHT);
+ y = (float)(-ACHANNEL_HEIGHT(ac));
for (ale = anim_data.first; ale; ale = ale->next) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -318,34 +318,34 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_ALL:
- draw_summary_channel(v2d, ale->data, y);
+ draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
break;
case ALE_SCE:
- draw_scene_channel(v2d, ads, ale->key_data, y);
+ draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
break;
case ALE_OB:
- draw_object_channel(v2d, ads, ale->key_data, y);
+ draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
break;
case ALE_ACT:
- draw_action_channel(v2d, adt, ale->key_data, y);
+ draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
break;
case ALE_GROUP:
- draw_agroup_channel(v2d, adt, ale->data, y);
+ draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
break;
case ALE_FCURVE:
- draw_fcurve_channel(v2d, adt, ale->key_data, y);
+ draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
break;
case ALE_GPFRAME:
- draw_gpl_channel(v2d, ads, ale->data, y);
+ draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
break;
case ALE_MASKLAY:
- draw_masklay_channel(v2d, ads, ale->data, y);
+ draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
break;
}
}
}
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
/* free tempolary channels used for drawing */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 8261a211ed0..55b087c40e7 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -333,7 +333,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through all channels, finding the first one that's selected */
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -343,8 +343,8 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
{
/* update best estimate */
- *min = (float)(y - ACHANNEL_HEIGHT_HALF);
- *max = (float)(y + ACHANNEL_HEIGHT_HALF);
+ *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* is this high enough priority yet? */
found = acf->channel_role;
@@ -358,7 +358,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
/* free all temp data */
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 7900217e28e..553be0ad290 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -213,7 +213,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
KeyframeEditFunc ok_cb, select_cb;
View2D *v2d = &ac->ar->v2d;
rctf rectf;
- float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac));
/* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
@@ -239,7 +239,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* get new vertical minimum extent of channel */
- ymin = ymax - ACHANNEL_STEP;
+ ymin = ymax - ACHANNEL_STEP(ac);
/* set horizontal range (if applicable) */
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
@@ -392,7 +392,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
KeyframeEditFunc ok_cb, select_cb;
View2D *v2d = &ac->ar->v2d;
rctf rectf, scaled_rectf;
- float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac));
/* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
@@ -426,10 +426,10 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* get new vertical minimum extent of channel */
- ymin = ymax - ACHANNEL_STEP;
+ ymin = ymax - ACHANNEL_STEP(ac);
/* compute midpoint of channel (used for testing if the key is in the region or not) */
- ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac);
/* if channel is mapped in NLA, apply correction
* - Apply to the bounds being checked, not all the keyframe points,
@@ -1351,6 +1351,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
bool found = false;
float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
float selx = 0.0f; /* frame of keyframe under mouse */
+ float key_hsize;
float x, y;
rctf rectf;
@@ -1360,11 +1361,16 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
- /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */
- UI_view2d_region_to_view(v2d, mval[0] - 7, mval[1], &rectf.xmin, &rectf.ymin);
- UI_view2d_region_to_view(v2d, mval[0] + 7, mval[1], &rectf.xmax, &rectf.ymax);
+ /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space),
+ * on either side of mouse click (size of keyframe icon)
+ */
+ key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; /* standard channel height (to allow for some slop) */
+ key_hsize = roundf(key_hsize / 2.0f); /* half-size (for either side), but rounded up to nearest int (for easier targetting) */
+
+ UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin);
+ UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax);
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 2d28108f544..07e1b2c4d79 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -618,7 +618,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
*/
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
- /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
+ /* Do not check whether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
if (fnmatch(pattern, file->relpath, 0) == 0) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
if (!match) {
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 3ac90200aea..b837e516422 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -1130,18 +1130,18 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
* - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
- height = (float)((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2));
+ height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2));
UI_view2d_totRect_set(v2d, ar->winx, height);
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -1152,7 +1152,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
}
@@ -1160,15 +1160,15 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
/* set blending again, as may not be set in previous step */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -1179,7 +1179,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 8ae5932f3fd..2582ba4be8d 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -525,12 +525,130 @@ static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
-
+/* Update F-Curve colors */
+static void graph_refresh_fcurve_colors(const bContext *C)
+{
+ bAnimContext ac;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ size_t items;
+ int filter;
+ int i;
+
+ if (ANIM_animdata_get_context(C, &ac) == false)
+ return;
+
+ UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW);
+
+ /* build list of F-Curves which will be visible as channels in channel-region
+ * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
+ * mismatch between channel-colors and the drawn curves
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop over F-Curves, assigning colors */
+ for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
+ FCurve *fcu = (FCurve *)ale->data;
+
+ /* set color of curve here */
+ switch (fcu->color_mode) {
+ case FCURVE_COLOR_CUSTOM:
+ {
+ /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors),
+ * which should be left alone... Nothing needs to be done here.
+ */
+ break;
+ }
+ case FCURVE_COLOR_AUTO_RGB:
+ {
+ /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors.
+ * TODO: find a way to module the hue so that not all curves have same color...
+ */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 0:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
+ case FCURVE_COLOR_AUTO_RAINBOW:
+ default:
+ {
+ /* determine color 'automatically' using 'magic function' which uses the given args
+ * of current item index + total items to determine some RGB color
+ */
+ getcolor_fcurve_rainbow(i, items, fcu->color);
+ break;
+ }
+ }
+ }
+
+ /* free temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
static void graph_refresh(const bContext *C, ScrArea *sa)
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
- bAnimContext ac;
/* updates to data needed depends on Graph Editor mode... */
switch (sipo->mode) {
@@ -558,119 +676,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
/* init/adjust F-Curve colors */
- if (ANIM_animdata_get_context(C, &ac)) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- size_t items;
- int filter;
- int i;
-
- UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW);
-
- /* build list of F-Curves which will be visible as channels in channel-region
- * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
- * mismatch between channel-colors and the drawn curves
- */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
- items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop over F-Curves, assigning colors */
- for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- FCurve *fcu = (FCurve *)ale->data;
-
- /* set color of curve here */
- switch (fcu->color_mode) {
- case FCURVE_COLOR_CUSTOM:
- {
- /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors),
- * which should be left alone... Nothing needs to be done here.
- */
- break;
- }
- case FCURVE_COLOR_AUTO_RGB:
- {
- /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors.
- * TODO: find a way to module the hue so that not all curves have same color...
- */
- float *col = fcu->color;
-
- switch (fcu->array_index) {
- case 0:
- UI_GetThemeColor3fv(TH_AXIS_X, col);
- break;
- case 1:
- UI_GetThemeColor3fv(TH_AXIS_Y, col);
- break;
- case 2:
- UI_GetThemeColor3fv(TH_AXIS_Z, col);
- break;
- default:
- /* 'unknown' color - bluish so as to not conflict with handles */
- col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
- break;
- }
- break;
- }
- case FCURVE_COLOR_AUTO_YRGB:
- {
- /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
- float *col = fcu->color;
-
- switch (fcu->array_index) {
- case 1:
- UI_GetThemeColor3fv(TH_AXIS_X, col);
- break;
- case 2:
- UI_GetThemeColor3fv(TH_AXIS_Y, col);
- break;
- case 3:
- UI_GetThemeColor3fv(TH_AXIS_Z, col);
- break;
-
- case 0:
- {
- /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
- float c1[3], c2[3];
- float h1[3], h2[3];
- float hresult[3];
-
- /* - get colors (rgb) */
- UI_GetThemeColor3fv(TH_AXIS_X, c1);
- UI_GetThemeColor3fv(TH_AXIS_Y, c2);
-
- /* - perform blending in HSV space (to keep brightness similar) */
- rgb_to_hsv_v(c1, h1);
- rgb_to_hsv_v(c2, h2);
-
- interp_v3_v3v3(hresult, h1, h2, 0.5f);
-
- /* - convert back to RGB for display */
- hsv_to_rgb_v(hresult, col);
- break;
- }
-
- default:
- /* 'unknown' color - bluish so as to not conflict with handles */
- col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
- break;
- }
- break;
- }
- case FCURVE_COLOR_AUTO_RAINBOW:
- default:
- {
- /* determine color 'automatically' using 'magic function' which uses the given args
- * of current item index + total items to determine some RGB color
- */
- getcolor_fcurve_rainbow(i, items, fcu->color);
- break;
- }
- }
- }
-
- /* free temp list */
- ANIM_animdata_freelist(&anim_data);
- }
+ graph_refresh_fcurve_colors(C);
}
static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 51f4a61047d..074368a82c5 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -65,7 +65,7 @@ static int edit_sensor_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "sensor", &RNA_Sensor);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
@@ -73,7 +73,7 @@ static int edit_controller_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
@@ -81,7 +81,7 @@ static int edit_actuator_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index b0adabe4d1d..5b3c062e16d 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -62,7 +62,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-
+#include "nla_private.h"
#include "nla_intern.h" /* own include */
@@ -145,6 +145,62 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d,
BLI_dlrbTree_free(&keys);
}
+/* Strip Markers ------------------------ */
+
+/* Markers inside an action strip */
+static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
+{
+ bAction *act = strip->act;
+ TimeMarker *marker;
+
+ if (ELEM(NULL, strip->act, strip->act->markers.first))
+ return;
+
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
+ float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
+
+ /* just a simple line for now */
+ // XXX: draw a triangle instead...
+ fdrawline(frame, yminc + 1, frame, ymaxc - 1);
+ }
+ }
+}
+
+/* Markers inside a NLA-Strip */
+static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
+{
+ glLineWidth(2.0);
+
+ if (strip->type == NLASTRIP_TYPE_CLIP) {
+ /* try not to be too conspicuous, while being visible enough when transforming */
+ if (strip->flag & NLASTRIP_FLAG_SELECT)
+ UI_ThemeColorShade(TH_STRIP_SELECT, -60);
+ else
+ UI_ThemeColorShade(TH_STRIP_SELECT, -40);
+
+ setlinestyle(3);
+
+ /* just draw the markers in this clip */
+ nla_actionclip_draw_markers(strip, yminc, ymaxc);
+
+ setlinestyle(0);
+ }
+ else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
+ /* just a solid color, so that it is very easy to spot */
+ UI_ThemeColorShade(TH_STRIP_SELECT, 20);
+
+ /* draw the markers in the first level of strips only (if they are actions) */
+ for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
+ if (nls->type == NLASTRIP_TYPE_CLIP) {
+ nla_actionclip_draw_markers(nls, yminc, ymaxc);
+ }
+ }
+ }
+
+ glLineWidth(1.0);
+}
+
/* Strips (Proper) ---------------------- */
/* get colors for drawing NLA-Strips */
@@ -361,6 +417,10 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
nla_draw_strip_curves(strip, yminc, ymaxc);
+ /* draw markings indicating locations of local markers (useful for lining up different actions) */
+ if ((snla->flag & SNLA_NOLOCALMARKERS) == 0)
+ nla_strip_draw_markers(strip, yminc, ymaxc);
+
/* draw strip outline
* - color used here is to indicate active vs non-active
*/
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index a2159696394..3e7e8ccc3f4 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -1856,6 +1856,7 @@ void NLA_OT_action_sync_length(wmOperatorType *ot)
static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
@@ -1887,7 +1888,7 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
/* multi-user? */
if (ID_REAL_USERS(strip->act) > 1) {
/* make a new copy of the action for us to use (it will have 1 user already) */
- bAction *new_action = BKE_action_copy(strip->act);
+ bAction *new_action = BKE_action_copy(bmain, strip->act);
/* decrement user count of our existing action */
id_us_min(&strip->act->id);
@@ -1945,6 +1946,7 @@ static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
@@ -1974,7 +1976,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
continue;
if (strip->act->id.us > 1) {
/* make a copy of the Action to work on */
- bAction *act = BKE_action_copy(strip->act);
+ bAction *act = BKE_action_copy(bmain, strip->act);
/* set this as the new referenced action, decrementing the users of the old one */
id_us_min(&strip->act->id);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 5c58e9b720c..cf6e2ac226e 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -255,7 +255,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
bAction *waction;
/* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
- waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
+ waction = wgroup->adt->action = BKE_action_copy(G.main, wgroup->adt->action);
/* now perform the moving */
BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 5615db1308f..7b7ea180604 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -402,7 +402,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
if (group_restrict_flag(gr, flag)) {
for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gob->ob))
continue;
gob->ob->restrictflag &= ~flag;
@@ -414,7 +414,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
}
else {
for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gob->ob))
continue;
/* not in editmode */
@@ -655,7 +655,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
int but_flag = UI_BUT_DRAG_LOCK;
gr = (Group *)tselem->id;
- if (gr->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gr))
but_flag |= UI_BUT_DISABLED;
UI_block_emboss_set(block, UI_EMBOSS_NONE);
@@ -828,7 +828,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
char buf[16] = "";
int but_flag = UI_BUT_DRAG_LOCK;
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
but_flag |= UI_BUT_DISABLED;
UI_block_emboss_set(block, UI_EMBOSS_NONE);
@@ -993,7 +993,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
else {
uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
- 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
+ 0.0, 0.0, 1.0, arg->alpha,
+ (arg->id && ID_IS_LINKED_DATABLOCK(arg->id)) ? arg->id->lib->name : "");
if (arg->id)
UI_but_drag_set_id(but, arg->id);
@@ -1561,7 +1562,7 @@ static void outliner_draw_tree_element(
else
offsx += 2 * ufac;
- if (tselem->type == 0 && tselem->id->lib) {
+ if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
if (tselem->id->tag & LIB_TAG_MISSING) {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 2618a14aa0d..b0cd3aabbfd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -55,6 +55,7 @@
#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_outliner_treehash.h"
@@ -231,7 +232,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
- else if (tselem->id->lib) {
+ else if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
@@ -243,8 +244,9 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
}
}
-void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void item_rename_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ARegion *ar = CTX_wm_region(C);
ReportList *reports = CTX_wm_reports(C); // XXX
@@ -306,7 +308,7 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
/* ID delete --------------------------------------------------- */
-static void id_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem)
+static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
@@ -315,16 +317,28 @@ static void id_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem)
BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
+ if (id->tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete id '%s', indirectly used datablocks need at least one user",
+ id->name);
+ return;
+ }
+
+
BKE_libblock_delete(bmain, id);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
void id_delete_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem,
- void *UNUSED(user_data))
+ bContext *C, ReportList *reports, Scene *UNUSED(scene),
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- id_delete(C, te, tselem);
+ id_delete(C, reports, te, tselem);
}
static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
@@ -338,7 +352,7 @@ static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeEl
"Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
return OPERATOR_CANCELLED;
}
- id_delete(C, te, tselem);
+ id_delete(C, reports, te, tselem);
return OPERATOR_FINISHED;
}
}
@@ -409,7 +423,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (old_id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(old_id)) {
BKE_reportf(op->reports, RPT_WARNING,
"Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
old_id->name);
@@ -520,7 +534,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
}
void id_remap_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
@@ -644,7 +658,7 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
/* XXX This does not work with several items
* (it is only called once in the end, due to the 'deferred' filebrowser invocation through event system...). */
void lib_relocate_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
@@ -686,7 +700,7 @@ void OUTLINER_OT_lib_reload(wmOperatorType *ot)
}
void lib_reload_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
@@ -773,8 +787,9 @@ int common_restrict_check(bContext *C, Object *ob)
/* Toggle Visibility ---------------------------------------- */
-void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_visibility_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *ob = (Object *)tselem->id;
@@ -789,21 +804,22 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_visibility_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
}
-static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
@@ -828,8 +844,9 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
/* Toggle Selectability ---------------------------------------- */
-void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -839,20 +856,21 @@ void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
}
-void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
}
-static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
@@ -876,8 +894,9 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
/* Toggle Renderability ---------------------------------------- */
-void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -887,20 +906,21 @@ void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
}
-void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
}
-static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
@@ -1962,7 +1982,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "child", childname);
ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
return OPERATOR_CANCELLED;
}
@@ -2010,7 +2030,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ob == par) {
return OPERATOR_CANCELLED;
}
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
return OPERATOR_CANCELLED;
}
@@ -2219,7 +2239,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_string_get(op->ptr, "object", obname);
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
- if (ELEM(NULL, ob, scene) || scene->id.lib != NULL) {
+ if (ELEM(NULL, ob, scene) || ID_IS_LINKED_DATABLOCK(scene)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index c6694b80df3..4ee8e55ce82 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -153,44 +153,58 @@ eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceO
int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive);
/* outliner_edit.c ---------------------------------------------- */
+typedef void (*outliner_operation_cb)(
+ struct bContext *C, struct ReportList *, struct Scene *scene,
+ struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *);
void outliner_do_object_operation_ex(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *),
- bool recurse_selected);
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb, bool recurse_selected);
void outliner_do_object_operation(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *));
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb);
int common_restrict_check(struct bContext *C, struct Object *ob);
int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
-void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-
-void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+
+void group_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+void item_rename_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
void lib_relocate_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
void lib_reload_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
void id_delete_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
void id_remap_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index e80ba5d40df..f3235d07757 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -57,6 +57,7 @@
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -134,15 +135,17 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
}
}
-static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* just set action to NULL */
BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
}
-static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_material_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
Material **matar = NULL;
int a, totcol = 0;
@@ -181,8 +184,9 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl
}
}
-static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_texture_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
MTex **mtex = NULL;
int a;
@@ -218,7 +222,7 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle
}
static void unlink_group_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -231,13 +235,14 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_libblock_unlink(bmain, group, false);
+ BKE_libblock_unlink(bmain, group, false, false);
BKE_libblock_free(bmain, group);
}
}
-static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void unlink_world_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Scene *parscene = (Scene *)tsep->id;
World *wo = (World *)tselem->id;
@@ -248,8 +253,8 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme
}
static void outliner_do_libdata_operation(
- bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *),
+ bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb,
void *user_data)
{
TreeElement *te;
@@ -260,11 +265,11 @@ static void outliner_do_libdata_operation(
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == 0) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
- operation_cb(C, scene, te, tsep, tselem, user_data);
+ operation_cb(C, reports, scene, te, tsep, tselem, user_data);
}
}
if (TSELEM_OPEN(tselem, soops)) {
- outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data);
+ outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data);
}
}
}
@@ -354,8 +359,9 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
}
/* ******************************************** */
-static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_select_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -366,8 +372,9 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
}
}
-static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void object_select_hierarchy_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* From where do i get the x,y coordinate of the mouse event ? */
wmWindow *win = CTX_wm_window(C);
@@ -377,8 +384,9 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl
}
-static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_deselect_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -389,14 +397,27 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t
}
}
-static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_delete_cb(
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
if (base == NULL)
base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return;
+ }
+
// check also library later
if (scene->obedit == base->object)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
@@ -410,45 +431,50 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_local_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ Main *bmain = CTX_data_main(C);
/* if the ID type has no special local function,
* just clear the lib */
- if (id_make_local(tselem->id, false) == false) {
- Main *bmain = CTX_data_main(C);
+ if (id_make_local(bmain, tselem->id, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
}
}
-static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_set_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_set(id);
}
-static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_clear_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_clear(id);
}
-static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_select_linked_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
ED_object_select_linked_by_id(C, id);
}
-static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -464,8 +490,9 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement
}
}
-static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_world_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -482,8 +509,9 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *
}
}
-static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_linkobs2scene_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
GroupObject *gob;
@@ -508,8 +536,9 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen
}
}
-static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_instance_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -523,9 +552,8 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
* \param select_recurse: Set to false for operations which are already recursively operating on their children.
*/
void outliner_do_object_operation_ex(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *),
- bool select_recurse)
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb, bool select_recurse)
{
TreeElement *te;
@@ -542,23 +570,24 @@ void outliner_do_object_operation_ex(
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
- operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
+ operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
select_handled = true;
}
}
if (TSELEM_OPEN(tselem, soops)) {
if ((select_handled == false) || select_recurse) {
- outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse);
+ outliner_do_object_operation_ex(
+ C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse);
}
}
}
}
void outliner_do_object_operation(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *))
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb)
{
- outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true);
+ outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true);
}
/* ******************************************** */
@@ -793,7 +822,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
-static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base)
{
Base *child_base, *base_next;
Object *parent;
@@ -806,17 +835,30 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
- base_next = outline_delete_hierarchy(C, scene, child_base);
+ base_next = outline_delete_hierarchy(C, reports, scene, child_base);
}
}
base_next = base->next;
+
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return base_next;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return base_next;
+ }
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
return base_next;
}
static void object_delete_hierarchy_cb(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+ bContext *C, ReportList *reports, Scene *scene,
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *obedit = scene->obedit;
@@ -831,7 +873,7 @@ static void object_delete_hierarchy_cb(
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
}
- outline_delete_hierarchy(C, scene, base);
+ outline_delete_hierarchy(C, reports, scene, base);
/* leave for ED_outliner_id_unref to handle */
#if 0
te->directdata = NULL;
@@ -889,7 +931,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
if (event == OL_OP_SELECT) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -899,7 +941,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -907,12 +949,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DESELECT) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DELETE) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
@@ -926,7 +968,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_DELETE_HIERARCHY) {
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
/* XXX: See OL_OP_DELETE comment above. */
outliner_cleanup_tree(soops);
@@ -936,30 +978,30 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_REMAP) {
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
str = "Remap ID";
}
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
- outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
}
else if (event == OL_OP_TOGVIS) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
str = "Toggle Visibility";
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
}
else if (event == OL_OP_TOGSEL) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
str = "Toggle Selectability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_TOGREN) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
str = "Toggle Renderability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
}
else if (event == OL_OP_RENAME) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
str = "Rename Object";
}
else {
@@ -1034,16 +1076,16 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_GROUPOP_UNLINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
break;
case OL_GROUPOP_LOCAL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
break;
case OL_GROUPOP_LINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
break;
case OL_GROUPOP_INSTANCE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(CTX_data_main(C));
break;
@@ -1051,19 +1093,19 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL);
break;
case OL_GROUPOP_REMAP:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
break;
case OL_GROUPOP_TOGVIS:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
break;
case OL_GROUPOP_TOGSEL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
break;
case OL_GROUPOP_TOGREN:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
break;
case OL_GROUPOP_RENAME:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
break;
default:
BLI_assert(0);
@@ -1148,25 +1190,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* unlink datablock from its parent */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Unlink world");
@@ -1180,7 +1222,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL:
{
/* make local */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
ED_undo_push(C, "Localized Data");
break;
}
@@ -1189,14 +1231,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Single-User World");
@@ -1211,21 +1253,21 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_DELETE:
{
if (idlevel > 0) {
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_delete_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
}
break;
}
case OUTLINER_IDOP_REMAP:
{
if (idlevel > 0) {
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
}
break;
}
case OUTLINER_IDOP_FAKE_ADD:
{
/* set fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Add Fake User");
@@ -1234,7 +1276,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_FAKE_CLEAR:
{
/* clear fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Clear Fake User");
@@ -1243,14 +1285,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
ED_undo_push(C, "Select");
break;
@@ -1324,7 +1366,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
case OL_LIB_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
@@ -1332,19 +1374,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
case OL_LIB_DELETE:
{
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_delete_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
break;
}
case OL_LIB_RELOCATE:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
break;
}
case OL_LIB_RELOAD:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_reload_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
break;
}
default:
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 83d8519a7cb..5f4c5837df4 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -489,7 +489,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
- if (ob->proxy && ob->id.lib == NULL)
+ if (ob->proxy && !ID_IS_LINKED_DATABLOCK(ob))
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 94ed280f792..e7428fd79d9 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -92,7 +92,7 @@ static int text_edit_poll(bContext *C)
if (!text)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
@@ -108,7 +108,7 @@ int text_space_edit_poll(bContext *C)
if (!st || !text)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
@@ -128,7 +128,7 @@ static int text_region_edit_poll(bContext *C)
if (!ar || ar->regiontype != RGN_TYPE_WINDOW)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index a8df5c02881..791ece14cb9 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -987,6 +987,11 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
dm_draw_flag |= DM_DRAW_USE_COLORS;
}
}
+ else {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
+ }
+ }
userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 3b1ce5f8ab0..9699b2d05d0 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -1399,8 +1399,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
float blend = z_abs * (1.0f - pow2f(la->spotblend));
/* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
if (blend != 0.0f && blend != z_abs) {
circ(0.0f, 0.0f, blend);
}
@@ -6221,7 +6221,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
}
else {
/* Sets the 'colindex' */
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1;
}
/* Sets the 'theme_id' or fallback to wire */
@@ -6903,7 +6903,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
!(G.f & G_RENDER_OGL))
{
/* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */
- drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us > 1);
+ drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ID_IS_LINKED_DATABLOCK(ob) || ob->id.us > 1);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index dcab05c80d6..3fa95315eba 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2594,6 +2594,7 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
GPU_horizon_update_color(&world->horr);
GPU_ambient_update_color(&world->ambr);
+ GPU_zenith_update_color(&world->zenr);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index afbf791b33a..2b0bd7690e2 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -109,7 +109,7 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) &&
- (v3d->camera->id.lib == NULL) &&
+ (!ID_IS_LINKED_DATABLOCK(v3d->camera)) &&
(v3d->flag2 & V3D_LOCK_CAMERA) &&
(rv3d->persp == RV3D_CAMOB));
}
@@ -3430,12 +3430,8 @@ static int render_border_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
- /* drawing a border surrounding the entire camera view switches off border rendering
- * or the border covers no pixels */
- if ((border.xmin <= 0.0f && border.xmax >= 1.0f &&
- border.ymin <= 0.0f && border.ymax >= 1.0f) ||
- (border.xmin == border.xmax || border.ymin == border.ymax))
- {
+ /* drawing a border outside the camera view switches off border rendering */
+ if ((border.xmin == border.xmax || border.ymin == border.ymax)) {
if (rv3d->persp == RV3D_CAMOB)
scene->r.mode &= ~R_BORDER;
else
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 8418cf0980c..31377d0fce8 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -346,7 +346,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->rv3d->persp = RV3D_PERSP;
}
- if (fly->rv3d->persp == RV3D_CAMOB && fly->v3d->camera->id.lib) {
+ if (fly->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(fly->v3d->camera)) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
return false;
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index c35646b9e92..bc7a9989c72 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -221,7 +221,7 @@ void ED_view3d_smooth_view_ex(
copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs);
sms.use_dyn_ofs = true;
- /* calcualte the final destination offset */
+ /* calculate the final destination offset */
view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs);
}
@@ -507,7 +507,7 @@ static int view3d_camera_to_view_poll(bContext *C)
if (ED_view3d_context_user_region(C, &v3d, &ar)) {
RegionView3D *rv3d = ar->regiondata;
- if (v3d && v3d->camera && v3d->camera->id.lib == NULL) {
+ if (v3d && v3d->camera && !ID_IS_LINKED_DATABLOCK(v3d->camera)) {
if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) {
if (rv3d->persp != RV3D_CAMOB) {
return 1;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 384da277612..c9e4bb301b8 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -505,7 +505,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->persp = RV3D_PERSP;
}
- if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->id.lib) {
+ if (walk->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(walk->v3d->camera)) {
BKE_report(op->reports, RPT_ERROR, "Cannot navigate a camera from an external library");
return false;
}
@@ -924,8 +924,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
/* stop the camera from a distance (camera height) */
- normalize_v3(nor);
- mul_v3_fl(nor, walk->view_height);
+ normalize_v3_length(nor, walk->view_height);
add_v3_v3(loc, nor);
sub_v3_v3v3(teleport->direction, loc, teleport->origin);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index c94b0d53468..6846ebc6680 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -100,7 +100,6 @@ static void doVertSlide(TransInfo *t, float perc);
static void drawEdgeSlide(TransInfo *t);
static void drawVertSlide(TransInfo *t);
-static void len_v3_ensure(float v[3], const float length);
static void postInputRotation(TransInfo *t, float values[3]);
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
@@ -4957,9 +4956,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
project_v3_v3v3(vec, vec, axis);
}
}
- normalize_v3(vec);
- mul_v3_fl(vec, distance);
- mul_v3_fl(vec, td->factor);
+ normalize_v3_length(vec, distance * td->factor);
add_v3_v3v3(td->loc, td->iloc, vec);
}
@@ -5375,7 +5372,9 @@ static void slide_origdata_init_data(
BMesh *bm = em->bm;
sod->origfaces = BLI_ghash_ptr_new(__func__);
- sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+ sod->bm_origfaces = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* we need to have matching customdata */
BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
}
@@ -5751,13 +5750,6 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[
}
}
-
-static void len_v3_ensure(float v[3], const float length)
-{
- normalize_v3(v);
- mul_v3_fl(v, length);
-}
-
/**
* Find the closest point on the ngon on the opposite side.
* used to set the edge slide distance for ngons.
@@ -5821,7 +5813,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
if (l->e == e_next) {
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
else {
/* When there is no edge to slide along,
@@ -5841,7 +5833,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
#if 0
/* rough guess, we can do better! */
- len_v3_ensure(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
+ normalize_v3_length(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
#else
/* be clever, check the opposite ngon edge to slide into.
* this gives best results */
@@ -5856,7 +5848,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
}
- len_v3_ensure(vec_accum, dist);
+ normalize_v3_length(vec_accum, dist);
}
#endif
}
@@ -5877,7 +5869,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
if (BM_loop_other_edge_loop(l, v)->e == e_next) {
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
copy_v3_v3(r_slide_vec, vec_accum);
@@ -5888,7 +5880,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
((l = l->radial_next) != l_first));
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
copy_v3_v3(r_slide_vec, vec_accum);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 13cc0c22778..d7b670b6476 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -187,9 +187,7 @@ static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3])
if (l < min_dist) {
float diff[3];
- normalize_v3_v3(diff, t->viewinv[2]);
- mul_v3_fl(diff, min_dist - l);
-
+ normalize_v3_v3_length(diff, t->viewinv[2], min_dist - l);
sub_v3_v3(t_con_center, diff);
}
}
@@ -225,9 +223,8 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
if (factor < 0.0f) factor *= -factor;
else factor *= factor;
- copy_v3_v3(out, axis);
- normalize_v3(out);
- mul_v3_fl(out, -factor); /* -factor makes move down going backwards */
+ /* -factor makes move down going backwards */
+ normalize_v3_v3_length(out, axis, -factor);
}
else {
float v[3], i1[3], i2[3];
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 4f06923c734..bb645562515 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -6238,7 +6238,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
/* select linked objects, but skip them later */
- if (ob->id.lib != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
td->flag |= TD_SKIP;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 78cebbf2c6e..96bdad9b3ae 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -562,7 +562,7 @@ static void recalcData_nla(TransInfo *t)
}
/* Use RNA to write the values to ensure that constraints on these are obeyed
- * (e.g. for transition strips, the values are taken from the neighbours)
+ * (e.g. for transition strips, the values are taken from the neighbors)
*
* NOTE: we write these twice to avoid truncation errors which can arise when
* moving the strips a large distance using numeric input [#33852]
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index b81fc471515..efee0fb8c7c 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -969,8 +969,7 @@ static void draw_manipulator_rotate(
vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
- normalize_v3(vec);
- mul_v3_fl(vec, 1.2f * size);
+ normalize_v3_length(vec, 1.2f * size);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3fv(vec);
@@ -1490,8 +1489,7 @@ static void draw_manipulator_rotate_cyl(
vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
- normalize_v3(vec);
- mul_v3_fl(vec, 1.2f * size);
+ normalize_v3_length(vec, 1.2f * size);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(vec);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index af465d70b61..ed6d49da681 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -68,13 +68,13 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
- BVHTreeFromMesh *bvh_trees[2];
+ BVHTreeFromMesh *bvh_trees[3];
} SnapObjectData_Mesh;
typedef struct SnapObjectData_EditMesh {
SnapObjectData sd;
- BVHTreeFromEditMesh *bvh_trees[2];
+ BVHTreeFromEditMesh *bvh_trees[3];
} SnapObjectData_EditMesh;
@@ -221,161 +221,115 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
/** \name Internal Object Snapping API
* \{ */
-static bool snapEdge(
- const ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3])
-{
- float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
- int result;
- bool retval = false;
+#define V3_MUL_ELEM(a, b) \
+ (a)[0] * (b)[0], \
+ (a)[1] * (b)[1], \
+ (a)[2] * (b)[2]
- copy_v3_v3(ray_end, ray_normal_local);
- mul_v3_fl(ray_end, 2000);
- add_v3_v3v3(ray_end, ray_start_local, ray_end);
+static bool test_vert(
+ const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3], const bool is_persp,
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3], float r_no[3])
+{
+ const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)};
+ const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
+ const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- /* dvec used but we don't care about result */
- result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec);
+ float depth;
+ float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth);
- if (result) {
- float edge_loc[3], vec[3];
- float mul;
+ if (depth < ray_depth_range[0]) {
+ return false;
+ }
- /* check for behind ray_start */
- sub_v3_v3v3(dvec, intersect, ray_start_local);
+ if (is_persp) {
+ dist_sq /= SQUARE(depth);
+ }
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+ copy_v3_v3(r_co, vco);
- if (mul > 1) {
- mul = 1;
- copy_v3_v3(intersect, v1co);
- }
- else if (mul < 0) {
- mul = 0;
- copy_v3_v3(intersect, v2co);
+ if (vno) {
+ copy_v3_v3(r_no, vno);
}
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
-
- copy_v3_v3(location, intersect);
-
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
-
- /* 10% threshold if edge is closer but a bit further
- * this takes care of series of connected edges a bit slanted w.r.t the viewport
- * otherwise, it would stick to the verts of the closest edge and not slide along merrily
- * */
- if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) {
- float n1[3], n2[3];
-
- *ray_depth = new_depth;
- retval = true;
-
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
-
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
-
- if (r_no) {
- normal_short_to_float_v3(n1, v1no);
- normal_short_to_float_v3(n2, v2no);
- interp_v3_v3v3(r_no, n2, n1, mul);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- copy_v3_v3(r_loc, location);
-
- *dist_px = new_dist;
- }
- }
+ *ray_depth = depth;
+ return true;
}
-
- return retval;
+ return false;
}
-static bool snapVertex(
- const 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])
+static bool test_edge(
+ const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3], const bool is_persp,
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3], float r_no[3])
{
- bool retval = false;
- float dvec[3];
-
- sub_v3_v3v3(dvec, vco, ray_start_local);
-
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
+ const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)};
+ const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)};
+ const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
+ const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- copy_v3_v3(location, vco);
+ float tmp_co[3], depth;
+ float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
+ if (depth < ray_depth_range[0]) {
+ return false;
+ }
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
+ if (is_persp) {
+ dist_sq /= SQUARE(depth);
+ }
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
- if (new_dist <= *dist_px && new_depth < *ray_depth) {
- *ray_depth = new_depth;
- retval = true;
+ tmp_co[0] /= scale[0];
+ tmp_co[1] /= scale[1];
+ tmp_co[2] /= scale[2];
- copy_v3_v3(r_loc, location);
+ copy_v3_v3(r_co, tmp_co);
- if (r_no) {
- copy_v3_v3(r_no, vno);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- *dist_px = new_dist;
+ if (r_no) {
+ sub_v3_v3v3(r_no, v1, v2);
}
- }
- return retval;
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
}
+#undef V3_MUL_ELEM
+
static bool snapArmature(
- const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ Object *ob, bArmature *arm, float obmat[4][4],
+ const short snap_to, const bool is_persp,
+ const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
+ float ray_origin_local[3], ray_normal_local[3];
bool retval = false;
invert_m4_m4(imat, obmat);
- mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_m4v3(ray_origin_local, imat, ray_origin);
mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
if (arm->edbo) {
EditBone *eBone;
@@ -385,21 +339,20 @@ static bool snapArmature(
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(
- ar, eBone->head, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ eBone->head, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
- retval |= snapVertex(
- ar, eBone->tail, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ eBone->tail, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(
- ar, eBone->head, NULL, eBone->tail, NULL,
- obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
+ retval |= test_edge(
+ eBone->head, eBone->tail, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
+ r_loc, NULL);
break;
}
}
@@ -419,38 +372,43 @@ static bool snapArmature(
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(
- ar, head_vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
- retval |= snapVertex(
- ar, tail_vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ head_vec, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
+ r_loc, NULL);
+ retval |= test_vert(
+ tail_vec, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(
- ar, head_vec, NULL, tail_vec, NULL,
- obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
+ retval |= test_edge(
+ head_vec, tail_vec, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
+ r_loc, NULL);
break;
}
}
}
}
-
- return retval;
+ if (retval) {
+ mul_m4_v3(obmat, r_loc);
+ return true;
+ }
+ return false;
}
static bool snapCurve(
- const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ Object *ob, Curve *cu, float obmat[4][4],
+ const short snap_to, const bool is_persp,
+ const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
+ float ray_origin_local[3], ray_normal_local[3];
bool retval = false;
int u;
@@ -463,12 +421,15 @@ static bool snapCurve(
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_origin_local, ray_origin);
copy_v3_v3(ray_normal_local, ray_normal);
- mul_m4_v3(imat, ray_start_local);
+ mul_m4_v3(imat, ray_origin_local);
mul_mat3_m4_v3(imat, ray_normal_local);
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (u = 0; u < nu->pntsu; u++) {
switch (snap_to) {
@@ -480,25 +441,25 @@ static bool snapCurve(
if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
break;
}
- retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) &&
!(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
{
- retval |= snapVertex(
- ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bezt[u].vec[0], NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
- retval |= snapVertex(
- ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bezt[u].vec[2], NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
}
}
@@ -507,9 +468,9 @@ static bool snapCurve(
if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
break;
}
- retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
}
}
@@ -517,15 +478,15 @@ static bool snapCurve(
/* curve is not visible outside editmode if nurb length less than two */
if (nu->pntsu > 1) {
if (nu->bezt) {
- retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
}
else {
- retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ retval |= test_vert(
+ nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
}
}
@@ -537,40 +498,38 @@ static bool snapCurve(
}
}
}
- return retval;
+ if (retval) {
+ mul_m4_v3(obmat, r_loc);
+ return true;
+ }
+ return false;
}
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- const ARegion *ar, Object *ob, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ Object *ob, float obmat[4][4],
+ const short snap_to, const bool is_persp,
+ const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
bool retval = false;
if (ob->transflag & OB_DUPLI) {
return retval;
}
/* for now only vertex supported */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
-
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- const float zero_co[3] = {0.0f};
- retval |= snapVertex(
- ar, zero_co, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ float ob_loc[3], ob_scale[3] = {1.0, 1.0, 1.0};
+ copy_v3_v3(ob_loc, obmat[3]);
+
+ retval |= test_vert(
+ ob_loc, NULL, ray_origin, ray_normal,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
break;
}
@@ -582,16 +541,19 @@ static bool snapEmpty(
}
static bool snapCamera(
- const ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ Scene *scene, Object *object, float obmat[4][4],
+ const short snap_to, const bool is_persp,
+ const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
MovieTracking *tracking;
- float ray_start_local[3], ray_normal_local[3];
+ float ray_origin_local[3], ray_normal_local[3];
if (clip == NULL) {
return retval;
@@ -622,7 +584,7 @@ static bool snapCamera(
reconstructed_camera_imat[4][4];
float (*vertex_obmat)[4];
- copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_origin_local, ray_origin);
copy_v3_v3(ray_normal_local, ray_normal);
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
@@ -641,21 +603,26 @@ static bool snapCamera(
copy_v3_v3(bundle_pos, track->bundle_pos);
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_m4_v3(orig_camera_imat, ray_start_local);
+ mul_m4_v3(orig_camera_imat, ray_origin_local);
mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
vertex_obmat = orig_camera_mat;
}
else {
mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- mul_m4_v3(imat, ray_start_local);
+ mul_m4_v3(imat, ray_origin_local);
mul_mat3_m4_v3(imat, ray_normal_local);
vertex_obmat = obmat;
}
- retval |= snapVertex(
- ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ float ob_scale[3];
+ mat4_to_size(ob_scale, vertex_obmat);
+
+ retval |= test_vert(
+ bundle_pos, NULL, ray_origin_local, ray_normal_local,
+ ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
r_loc, NULL);
+
+ mul_m4_v3(vertex_obmat, r_loc);
}
}
@@ -674,16 +641,61 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
+struct NearestDM_Data {
+ void *bvhdata;
+ bool is_persp;
+ const float *ray_depth_range;
+
+ float *ray_depth;
+};
+
+static void test_vert_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BVHTreeFromMesh *data = ndata->bvhdata;
+ const MVert *vert = data->vert + index;
+
+ if (test_vert(
+ vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, NULL))
+ {
+ normal_short_to_float_v3(nearest->no, vert->no);
+ nearest->index = index;
+ }
+}
+
+static void test_edge_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BVHTreeFromMesh *data = ndata->bvhdata;
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+
+ if (test_edge(
+ vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
+
static bool snapDerivedMesh(
SnapObjectContext *sctx,
- Object *ob, DerivedMesh *dm, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to, bool do_bb,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth, unsigned int ob_index,
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ const short snap_to, const bool is_persp, bool do_bb,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
{
- const ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (snap_to == SCE_SNAP_MODE_FACE) {
@@ -703,10 +715,7 @@ static bool snapDerivedMesh(
}
{
- const bool do_ray_start_correction = (
- ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
- (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
- bool need_ray_start_correction_init = do_ray_start_correction;
+ bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp;
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -772,6 +781,9 @@ static bool snapDerivedMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -793,10 +805,8 @@ static bool snapDerivedMesh(
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -804,144 +814,154 @@ static bool snapDerivedMesh(
case SCE_SNAP_MODE_FACE:
bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
break;
+ case SCE_SNAP_MODE_EDGE:
+ bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
+ break;
case SCE_SNAP_MODE_VERTEX:
bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
break;
}
}
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ /* 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 (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);
+ if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */
+ if (need_ray_start_correction_init) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ if (treedata && treedata->tree != NULL) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ }
+ }
+ }
+ 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 + ray_depth_range[0]);
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+ 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]);
+ }
+ }
}
}
}
- /* 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) {
+ else {
+ /* Vert & edge use nearly identical logic. */
+ BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE));
+
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;
- }
+ BVHTreeNearest nearest;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index,
- data.dm = dm;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit;
+ nearest.index = -1;
+ nearest.dist_sq = *dist_to_ray_sq;
- hit.index = -1;
- hit.dist = local_depth;
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = treedata;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
- copy_v3_v3(r_no, hit.no);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
-
- retval = true;
-
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
- }
- }
- }
- }
- break;
- }
- case SCE_SNAP_MODE_VERTEX:
- {
- BVHTreeNearest nearest;
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
- nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata->tree &&
- BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
- {
- const MVert *v = &treedata->vert[nearest.index];
- float vno[3];
- normal_short_to_float_v3(vno, v->no);
- retval = snapVertex(
- ar, v->co, vno, obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
- break;
- }
- case SCE_SNAP_MODE_EDGE:
+ BVHTree_NearestToRayCallback callback =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_vert_depth_cb : test_edge_depth_cb;
+
+ if (treedata->tree &&
+ (is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, callback, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, callback, &userdata)) != -1)
{
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
-
- for (int i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- retval |= snapEdge(
- ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
- obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_to_ray_sq = nearest.dist_sq;
- break;
+ retval = true;
}
}
@@ -955,17 +975,51 @@ static bool snapDerivedMesh(
return retval;
}
+static void test_bmvert_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BMEditMesh *em = ndata->bvhdata;
+ BMVert *eve = BM_vert_at_index(em->bm, index);
+
+ if (test_vert(
+ eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
+
+static void test_bmedge_depth_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const BMEditMesh *em = ndata->bvhdata;
+ BMEdge *eed = BM_edge_at_index(em->bm, index);
+
+ if (test_edge(
+ eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
+ ndata->ray_depth, &nearest->dist_sq,
+ nearest->co, nearest->no))
+ {
+ nearest->index = index;
+ }
+}
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,
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ const short snap_to, const bool is_persp,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
{
- const ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (snap_to == SCE_SNAP_MODE_FACE) {
@@ -985,31 +1039,17 @@ static bool snapEditMesh(
}
{
- 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;
+ float ray_normal_local[3];
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;
@@ -1027,6 +1067,9 @@ static bool snapEditMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -1041,10 +1084,8 @@ static bool snapEditMesh(
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -1065,6 +1106,23 @@ static bool snapEditMesh(
}
break;
}
+ case SCE_SNAP_MODE_EDGE:
+ {
+ BLI_bitmap *edges_mask = NULL;
+ int edges_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_edge_fn) {
+ edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
+ edges_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_EDGES_OF_MESH, em->bm, edges_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
+ sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
+ if (edges_mask) {
+ MEM_freeN(edges_mask);
+ }
+ break;
+ }
case SCE_SNAP_MODE_VERTEX:
{
BLI_bitmap *verts_mask = NULL;
@@ -1085,139 +1143,153 @@ static bool snapEditMesh(
}
}
- /* 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!
- */
- float len_diff = 0.0f;
- 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. */
- if (BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -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;
- }
- }
- }
-
- 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;
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ float ray_start_local[3];
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
- hit.index = -1;
- hit.dist = local_depth;
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
+ float local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
+ /* 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!
+ */
+ float len_diff = 0.0f;
+ if (sctx->use_v3d && !is_persp) { /* 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. */
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, NULL, NULL) != -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;
- }
- }
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ 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 + ray_depth_range[0]);
+ local_depth -= len_diff;
}
}
- break;
}
- case SCE_SNAP_MODE_VERTEX:
- {
- BVHTreeNearest nearest;
+ 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;
- 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)
+ BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -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);
+ 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_EDGE:
+ }
+ else {
+ /* Vert & edge use nearly identical logic. */
+ BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE));
+
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = em;
+ userdata.is_persp = is_persp;
+ userdata.ray_depth_range = ray_depth_range;
+ userdata.ray_depth = ray_depth;
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ BVHTree_NearestToRayCallback callback =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_bmvert_depth_cb : test_bmedge_depth_cb;
+
+ if (treedata->tree &&
+ (is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, callback, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, callback, &userdata)) != -1)
{
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
- int totedge = em->bm->totedge;
- for (int i = 0; i < totedge; i++) {
- BMEdge *eed = BM_edge_at_index(em->bm, i);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
- !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
- !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
- {
- short v1no[3], v2no[3];
- normal_float_to_short_v3(v1no, eed->v1->no);
- normal_float_to_short_v3(v2no, eed->v2->no);
- retval |= snapEdge(
- ar, eed->v1->co, v1no, eed->v2->co, v2no,
- obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
+ *dist_to_ray_sq = nearest.dist_sq;
- break;
+ retval = true;
}
}
@@ -1231,18 +1303,28 @@ static bool snapEditMesh(
return retval;
}
+/**
+ * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
+ * \param ray_depth_range:
+ * - 0: distance from the ray_origin to the clipping plane min (can be negative).
+ * - 1: maximum distance, elements outside this are ignored.
+ * \param ray_depth: maximum depth allowed for r_co.
+ *
+ * \note Duplicate args here are documented at #snapObjectsRay
+ */
static bool snapObject(
SnapObjectContext *sctx,
- Object *ob, float obmat[4][4], bool use_obedit, const short snap_to,
- const float mval[2], float *dist_px, const unsigned int ob_index,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth,
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit, const short snap_to,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- const ARegion *ar = sctx->v3d_data.ar;
+ const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp;
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1251,9 +1333,10 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_origin,
- ray_depth, ob_index,
+ sctx, ob, em, obmat, ob_index,
+ snap_to, is_persp,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no, r_index,
r_hit_list);
}
@@ -1269,36 +1352,42 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, mval, dist_px, snap_to, true,
- ray_start, ray_normal, ray_origin,
- ray_depth, ob_index,
- r_loc, r_no, r_index, r_hit_list);
+ sctx, ob, dm, obmat, ob_index,
+ snap_to, is_persp, true,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
+ r_loc, r_no,
+ r_index, r_hit_list);
dm->release(dm);
}
}
else if (ob->type == OB_ARMATURE) {
retval = snapArmature(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ob, ob->data, obmat, snap_to, is_persp,
+ ray_origin, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no);
}
else if (ob->type == OB_CURVE) {
retval = snapCurve(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ob, ob->data, obmat, snap_to, is_persp,
+ ray_origin, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no);
}
else if (ob->type == OB_EMPTY) {
retval = snapEmpty(
- ar, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ ob, obmat, snap_to, is_persp,
+ ray_origin, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no);
}
else if (ob->type == OB_CAMERA) {
retval = snapCamera(
- ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
+ sctx->scene, ob, obmat, snap_to, is_persp,
+ ray_origin, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no);
}
@@ -1312,18 +1401,64 @@ static bool snapObject(
return retval;
}
+/**
+ * Main Snapping Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the closest snap element ray.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \param snap_select: from enum SnapSelect.
+ *
+ * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
+ * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
+ * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
+ * \param ray_normal: Unit length direction of the ray.
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared.
+ * resulting of the function #dist_px_to_dist3d_or_tangent.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Hit location.
+ * \param r_no: Hit normal (optional).
+ * \param r_index: Hit index or -1 when no valid index is found.
+ * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * \param r_ob: Hit object.
+ * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ *
+ */
static bool snapObjectsRay(
SnapObjectContext *sctx,
const unsigned short snap_to, const SnapSelect snap_select,
const bool use_object_edit_cage,
- 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 ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
bool retval = false;
+
+ float dvec[3];
+ sub_v3_v3v3(dvec, ray_start, ray_origin);
+
+ const float ray_depth_range[2] = {
+ dot_v3v3(dvec, ray_normal),
+ *ray_depth,
+ };
+
unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
Base *base_act = sctx->scene->basact;
@@ -1357,9 +1492,10 @@ static bool snapObjectsRay(
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, dupli_snap, dupli_ob->mat, ob_index++,
+ use_obedit_dupli, snap_to,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1370,9 +1506,10 @@ static bool snapObjectsRay(
Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
- sctx, ob_snap, ob->obmat, use_obedit, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob_snap, ob->obmat, ob_index++,
+ use_obedit, snap_to,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -1474,15 +1611,18 @@ bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
const unsigned short snap_to,
const struct SnapObjectParams *params,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const float ray_start[3], const float ray_normal[3],
+ float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
+ float dist_to_ray_sq = 0.0f;
+
return snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- NULL, NULL,
- ray_start, ray_normal, ray_start, ray_depth,
+ ray_start, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -1501,6 +1641,8 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth, bool sort,
ListBase *r_hit_list)
{
+ float dist_to_ray_sq = 0.0f;
+
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1512,8 +1654,8 @@ bool ED_transform_snap_object_project_ray_all(
bool retval = snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- NULL, NULL,
- ray_start, ray_normal, ray_start, &ray_depth,
+ ray_start, ray_start, ray_normal,
+ &ray_depth, &dist_to_ray_sq,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1622,6 +1764,21 @@ static bool transform_snap_context_project_view3d_mixed_impl(
}
/**
+ * From a threshold (maximum distance to snap in pixels) returns:
+ *
+ * - The *real* distance (3D) if you are in orthographic-view.
+ * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
+ */
+static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
+{
+ const RegionView3D *rv3d = ar->regiondata;
+ if (ar->winx >= ar->winy)
+ return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
+ else
+ return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
+}
+
+/**
* Convenience function for performing snapping.
*
* Given a 2D region value, snap to vert/edge/face.
@@ -1672,12 +1829,40 @@ bool ED_transform_snap_object_project_view3d_ex(
return false;
}
- return snapObjectsRay(
+ float radius, dist_to_ray_sq = 0.0f;
+ if (dist_px) {
+ radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px);
+ /**
+ * Workaround to use of cone (Instead of project the radius on view plane):
+ * In perspective view, the radius of the cone may decrease depending on the ray direction.
+ * This is more evident with small values of the `Viewport lens angle`.
+ * The threshold becomes distorted that way.
+ */
+ RegionView3D *rv3d = sctx->v3d_data.ar->regiondata;
+ if (rv3d->is_persp) {
+ float view_dir[3];
+ negate_v3_v3(view_dir, rv3d->viewinv[2]);
+ normalize_v3(view_dir);
+ radius *= dot_v3v3(ray_normal, view_dir);
+ }
+
+ dist_to_ray_sq = SQUARE(radius);
+ }
+
+ if (snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- mval, dist_px,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, NULL, NULL, NULL);
+ ray_origin, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq,
+ r_loc, r_no, r_index, NULL, NULL, NULL))
+ {
+ if (dist_px) {
+ *dist_px *= sqrtf(dist_to_ray_sq) / radius;
+ }
+ return true;
+ }
+
+ return false;
}
bool ED_transform_snap_object_project_view3d(
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index e2f60955c81..1f1a778cac7 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -105,7 +105,7 @@ void ED_editors_init(bContext *C)
ob->mode = OB_MODE_OBJECT;
data = ob->data;
- if (ob == obact && !ob->id.lib && !(data && data->lib))
+ if (ob == obact && !ID_IS_LINKED_DATABLOCK(ob) && !(data && ID_IS_LINKED_DATABLOCK(data)))
ED_object_toggle_modes(C, mode);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 4713ea73b58..bdfff123aa4 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -743,9 +743,9 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
/* Sanity check, a single nan/inf point causes the entire result to be invalid.
* Note that values within the calculation may _become_ non-finite,
- * so the rest of the code still needs to take this possability into account. */
+ * so the rest of the code still needs to take this possibility into account. */
for (int i = 0; i < 3; i++) {
- if (UNLIKELY(!finite(v->co[i]))) {
+ if (UNLIKELY(!isfinite(v->co[i]))) {
v->co[i] = 0.0f;
}
}
@@ -2804,7 +2804,7 @@ static PBool p_chart_abf_solve(PChart *chart)
static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
{
- if (pin1 == pin2) {
+ if (!*pin1 || !*pin2 || *pin1 == *pin2) {
/* degenerate case */
PFace *f = chart->faces;
*pin1 = f->edge->vert;
@@ -3051,7 +3051,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
p_chart_boundaries(chart, NULL, &outer);
/* outer can be NULL with non-finite coords. */
- if (outer && !p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) {
+ if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
p_chart_extrema_verts(chart, &pin1, &pin2);
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 5c361de8d8d..f63cf771120 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -907,7 +907,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
material_index++;
} // loop over strokes
- test_object_materials(freestyle_bmain, (ID *)mesh);
+ test_object_materials(object_mesh, (ID *)mesh);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h
index 53bc23c6eb3..8d06865e31b 100644
--- a/source/blender/freestyle/intern/geometry/normal_cycle.h
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.h
@@ -63,13 +63,13 @@ template <class T> inline void ogf_swap(T& x, T& y)
//_________________________________________________________
/**
-* NormalCycle evaluates the curvature tensor in function
-* of a set of dihedral angles and associated vectors.
-* Reference:
-* Restricted Delaunay Triangulation and Normal Cycle,
-* D. Cohen-Steiner and J.M. Morvan,
-* SOCG 2003
-*/
+ * NormalCycle evaluates the curvature tensor in function
+ * of a set of dihedral angles and associated vectors.
+ * Reference:
+ * Restricted Delaunay Triangulation and Normal Cycle,
+ * D. Cohen-Steiner and J.M. Morvan,
+ * SOCG 2003
+ */
class NormalCycle {
public:
NormalCycle();
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
index e35076ec7fe..96a8bee9394 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -121,7 +121,7 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
return NULL;
}
/* If at the start of the iterator, only return the object
- * and don't increment, to keep for-loops in sync */
+ * and don't increment, to keep for-loops in sync */
else if (self->at_start) {
self->at_start = false;
}
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index a00f983bbcf..220c966a5d0 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -298,9 +298,9 @@ public:
inline void setShininess(const float s);
/*! Sets the line color priority.
- * \param priority
- * Priority
- */
+ * \param priority
+ * Priority
+ */
inline void setPriority(const int priority);
/* operators */
diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
index 4b079df5632..8dc93d84201 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
@@ -52,16 +52,6 @@ public:
return _SceneRenderLayer;
}
- inline void setSceneRenderLayer(Scene& scene)
- {
- _Scene = scene;
- }
-
- inline void setSceneRenderLayer(SceneRenderLayer& srl)
- {
- _SceneRenderLayer = srl;
- }
-
/*! Accept the corresponding visitor */
virtual void accept(SceneVisitor& v);
diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
index f650e32b278..c65f121e9ba 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
@@ -46,8 +46,8 @@ namespace Predicates1D {
// DensityLowerThanUP1D
/*! Returns true if the density evaluated for the
-* Interface1D is less than a user-defined density value.
-*/
+ * Interface1D is less than a user-defined density value.
+ */
class DensityLowerThanUP1D : public UnaryPredicate1D
{
public:
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
index e3842f45eb0..cc935a7e311 100644
--- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
@@ -619,9 +619,9 @@ public:
}
/*! Builds the shader.
- * \param nodetree
- * A node tree (of new shading nodes) to define textures.
- */
+ * \param nodetree
+ * A node tree (of new shading nodes) to define textures.
+ */
BlenderTextureShader(bNodeTree *nodetree) : StrokeShader()
{
_nodeTree = nodetree;
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index 5f0b4eab309..db96a27e073 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -605,15 +605,15 @@ public:
*/
int Resample(float iSampling);
- /*! Removes all vertices from the Stroke.
- */
- void RemoveAllVertices();
+ /*! Removes all vertices from the Stroke.
+ */
+ void RemoveAllVertices();
/*! Removes the stroke vertex iVertex
- * from the stroke.
- * The length and curvilinear abscissa are updated
- * consequently.
- */
+ * from the stroke.
+ * The length and curvilinear abscissa are updated
+ * consequently.
+ */
void RemoveVertex(StrokeVertex *iVertex);
/*! Inserts the stroke vertex iVertex in the stroke before next.
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
index 85c6390cb9e..a97e60d5f60 100644
--- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
@@ -640,7 +640,7 @@ void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace)
normal_vec = wxf->GetVertexNormal(v); // FIXME: what about e1 ^ e2 ?
radial_normal_vec = er_vec ^ normal_vec;
- // Test wether the radial plan intersects with the edge at the opposite of v.
+ // Test whether the radial plan intersects with the edge at the opposite of v.
res = GeomUtils::intersectRayPlane(opposite_vertex_a->GetVertex(), opposite_edge->GetVec(),
radial_normal_vec, -(v_vec * radial_normal_vec),
t, 1.0e-06);
diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h
index 647a3a530c6..f0009fca6ea 100644
--- a/source/blender/freestyle/intern/view_map/Functions0D.h
+++ b/source/blender/freestyle/intern/view_map/Functions0D.h
@@ -429,12 +429,12 @@ public:
// QiF0D
/*! Returns the quantitative invisibility of this Interface0D.
-* This evaluation can be ambiguous (in the case of a TVertex for example).
-* This functor tries to remove this ambiguity using the context offered by the 1D element to which the
-* Interface0DIterator& belongs to.
-* However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
-* should implement its own getQIF0D functor.
-*/
+ * This evaluation can be ambiguous (in the case of a TVertex for example).
+ * This functor tries to remove this ambiguity using the context offered by the 1D element to which the
+ * Interface0DIterator& belongs to.
+ * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
+ * should implement its own getQIF0D functor.
+ */
class QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int>
{
public:
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 0b20c9f6aa2..b9924e6ad95 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1204,9 +1204,9 @@ public:
}
/*! Returns the index of the material of the face lying on the
- * right of the FEdge. If this FEdge is a border,
- * it has no Face on its right and therefore, no material.
- */
+ * right of the FEdge. If this FEdge is a border,
+ * it has no Face on its right and therefore, no material.
+ */
inline unsigned aFrsMaterialIndex() const
{
return _aFrsMaterialIndex;
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 97dcc86cf31..989e101dd1a 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -372,21 +372,21 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V
f2 = e->GetbFace();
/* We are solving for the values of the curvature tensor
- * B = [ a b ; b c ].
- * The computations here are from section 5 of [Meyer et al 2002].
- *
- * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
- * by setting the derivatives of the error E to zero (section 5.3).
- *
- * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
- * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
- *
- * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
- * factor because the solution of the linear equations doesn't rely on it.
- *
- * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
- * terms that are the constant factors in the equations.
- */
+ * B = [ a b ; b c ].
+ * The computations here are from section 5 of [Meyer et al 2002].
+ *
+ * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
+ * by setting the derivatives of the error E to zero (section 5.3).
+ *
+ * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
+ * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
+ *
+ * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
+ * factor because the solution of the linear equations doesn't rely on it.
+ *
+ * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
+ * terms that are the constant factors in the equations.
+ */
/* find the vector from v along edge e */
vec_edge = Vec3r(-1 * e->GetVec());
@@ -400,7 +400,7 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V
/* section 5.2 */
/* I don't like performing a minimization where some of the weights can be negative (as can be the case
- * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
+ * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
weight = 0.0;
if (!triangle_obtuse(v, f1)) {
weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 7972d138b9b..b693d473bd8 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -223,7 +223,7 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* build */
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
- const int (*face_vert_indices)[4],
+ const int (*face_vert_indices)[3],
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri,
const struct MVert *verts,
const int *face_indices,
@@ -240,7 +240,7 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
void GPU_update_mesh_pbvh_buffers(
GPU_PBVH_Buffers *buffers, const struct MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[4], bool show_diffuse_color);
+ const int (*face_vert_indices)[3], bool show_diffuse_color);
void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 3413ee0d161..202e5fd3ad7 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -332,6 +332,7 @@ void GPU_mist_update_enable(short enable);
void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]);
void GPU_horizon_update_color(float color[3]);
void GPU_ambient_update_color(float color[3]);
+void GPU_zenith_update_color(float color[3]);
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 36d297fb9fe..c663af0ccbb 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -1033,7 +1033,7 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key,
void GPU_update_mesh_pbvh_buffers(
GPU_PBVH_Buffers *buffers, const MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[4], bool show_diffuse_color)
+ const int (*face_vert_indices)[3], bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j;
@@ -1161,7 +1161,7 @@ void GPU_update_mesh_pbvh_buffers(
}
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
- const int (*face_vert_indices)[4],
+ const int (*face_vert_indices)[3],
const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri,
const MVert *mvert,
const int *face_indices,
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 79d11ae0972..ba78c347e99 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -88,6 +88,7 @@ static struct GPUWorld {
float mistcol[4];
float horicol[3];
float ambcol[4];
+ float zencol[3];
} GPUWorld;
struct GPUMaterial {
@@ -1648,6 +1649,11 @@ void GPU_ambient_update_color(float color[3])
GPUWorld.ambcol[3] = 1.0f;
}
+void GPU_zenith_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.zencol, color);
+}
+
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
GPUMaterial *mat = shi->gpumat;
@@ -1704,6 +1710,37 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
ulinfac, ulogfac, &shr->spec);
}
+ /* environment lighting */
+ if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) &&
+ (world->mode & WO_ENV_LIGHT) &&
+ (mat->scene->r.mode & R_SHADOW) &&
+ !BKE_scene_use_new_shading_nodes(mat->scene))
+ {
+ if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) &&
+ (GPU_link_changed(shi->refl) || ma->ref != 0.0f))
+ {
+ if (world->aocolor != WO_AOPLAIN) {
+ if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr)))
+ {
+ GPUNodeLink *fcol, *f;
+ GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
+ GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
+ GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol);
+ GPU_link(mat, "env_apply", shr->combined,
+ GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
+ GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol,
+ GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined);
+ }
+ }
+ else {
+ GPUNodeLink *f;
+ GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
+ GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
+ GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined);
+ }
+ }
+ }
+
/* ambient color */
if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
@@ -2527,7 +2564,7 @@ int GPU_lamp_shadow_bind_code(GPULamp *lamp)
float *GPU_lamp_dynpersmat(GPULamp *lamp)
{
- return lamp->dynpersmat ? (float *)lamp->dynpersmat : NULL;
+ return &lamp->dynpersmat[0][0];
}
int GPU_lamp_shadow_layer(GPULamp *lamp)
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 9914c4bb362..f3bd817a7cc 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1358,6 +1358,13 @@ void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
value = 1.0;
}
+void mtex_cube_map_refl_from_refldir(
+ samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
+{
+ color = textureCube(ima, reflecteddirection);
+ value = 1.0;
+}
+
void mtex_cube_map_refl(
samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix,
out float value, out vec4 color)
@@ -2182,6 +2189,13 @@ void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
}
+void env_apply(vec4 col, vec4 hor, vec4 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
+{
+ vec3 vv = normalize(vm[2].xyz);
+ float skyfac = 0.5 * (1.0 + dot(vn, -vv));
+ outcol = col + f * mix(hor, zen, skyfac);
+}
+
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
{
outcol = col + f * col1;
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index b3c83bffb3f..6ea311b2c7b 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -50,6 +50,8 @@
#include <string.h> /* memcpy */
+#define USE_NONUNIFORM_SCALE
+
/* ********************** THE IK SOLVER ******************* */
/* allocates PoseTree, and links that to root bone/channel */
@@ -525,10 +527,10 @@ void iksolver_initialize_tree(struct Scene *UNUSED(scene), struct Object *ob, fl
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime)
+void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- while (pchan->iktree.first) {
- PoseTree *tree = pchan->iktree.first;
+ while (pchan_root->iktree.first) {
+ PoseTree *tree = pchan_root->iktree.first;
int a;
/* stop on the first tree that isn't a standard IK chain */
@@ -542,6 +544,19 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose
/* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */
tree->pchan[a]->flag |= POSE_CHAIN;
}
+
+#ifdef USE_NONUNIFORM_SCALE
+ float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__);
+
+ for (a = 0; a < tree->totchannel; a++) {
+ mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat);
+
+ /* make uniform at y scale since this controls the length */
+ normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]);
+ normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]);
+ }
+#endif
+
/* 5. execute the IK solver */
execute_posetree(scene, ob, tree);
@@ -556,8 +571,16 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose
where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
}
+#ifdef USE_NONUNIFORM_SCALE
+ for (a = 0; a < tree->totchannel; a++) {
+ normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]);
+ normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]);
+ }
+ MEM_freeN(pchan_scale_data);
+#endif
+
/* 7. and free */
- BLI_remlink(&pchan->iktree, tree);
+ BLI_remlink(&pchan_root->iktree, tree);
free_posetree(tree);
}
}
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h
index c2ae4f937e7..07264280a25 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.h
+++ b/source/blender/ikplugin/intern/iksolver_plugin.h
@@ -41,7 +41,7 @@ extern "C" {
#endif
void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
#ifdef __cplusplus
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index d4814a4e3a2..b8ed780397f 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1770,7 +1770,7 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime)
+void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
if (!ob->pose->ikdata) {
// IK tree not yet created, no it now
@@ -1784,7 +1784,7 @@ void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseCha
if (!ikparam) ikparam = &DefIKParam;
for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) {
- if (ikscene->channels[0].pchan == pchan) {
+ if (ikscene->channels[0].pchan == pchan_root) {
float timestep = scene->r.frs_sec_base / scene->r.frs_sec;
if (ob->pose->flag & POSE_GAME_ENGINE) {
timestep = ob->pose->ctime;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h
index 0500125b4c7..bcd95bc31ca 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.h
+++ b/source/blender/ikplugin/intern/itasc_plugin.h
@@ -41,7 +41,7 @@ extern "C" {
#endif
void itasc_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime);
void itasc_clear_data(struct bPose *pose);
void itasc_clear_cache(struct bPose *pose);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 5eb7afb4e00..60701e96edb 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -268,6 +268,8 @@ typedef struct PreviewImage {
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
+#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL)
+
#ifdef GS
# undef GS
#endif
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 4d82e4528d6..9a19606d6c8 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -330,7 +330,7 @@ typedef enum ePchan_DrawFlag {
/* PoseChannel->bboneflag */
typedef enum ePchan_BBoneFlag {
- /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbours */
+ /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbors */
PCHAN_BBONE_CUSTOM_HANDLES = (1 << 1),
/* Evaluate start handle as being "relative" */
PCHAN_BBONE_CUSTOM_START_REL = (1 << 2),
@@ -627,8 +627,9 @@ typedef enum eDopeSheet_FilterFlag {
typedef enum eDopeSheet_Flag {
ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */
ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */
-
+
ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */
+ ADS_FLAG_NO_DB_SORT = (1 << 3), /* do not sort datablocks (mostly objects) by name (NOTE: potentially expensive operation) */
/* NOTE: datablock filter flags continued (1 << 10) onwards... */
} eDopeSheet_Flag;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 61169e4b1b1..902fa4ce987 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -424,6 +424,7 @@ typedef enum eBezTriple_KeyframeType {
BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */
BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */
BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */
+ BEZT_KEYTYPE_MOVEHOLD = 4, /* one end of a 'moving hold' */
} eBezTriple_KeyframeType;
/* checks if the given BezTriple is selected */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index d62369803d6..77877f7bada 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -74,7 +74,9 @@ enum eSDNA_StructCompare {
SDNA_CMP_NOT_EQUAL = 2,
};
-struct SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap);
+struct SDNA *DNA_sdna_from_data(
+ const void *data, const int datalen,
+ bool do_endian_swap, bool data_alloc);
void DNA_sdna_free(struct SDNA *sdna);
int DNA_struct_find_nr(struct SDNA *sdna, const char *str);
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 2928e10d215..87b6813712f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -902,6 +902,7 @@ typedef struct GameData {
#define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15)
#define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16)
#define GAME_NO_MATERIAL_CACHING (1 << 17)
+#define GAME_GLSL_NO_ENV_LIGHTING (1 << 18)
/* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */
/* GameData.playerflag */
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
index cb7a371c7c5..791aca77558 100644
--- a/source/blender/makesdna/DNA_sdna_types.h
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -35,8 +35,9 @@
#
#
typedef struct SDNA {
- char *data; /* full copy of 'encoded' data */
+ const char *data; /* full copy of 'encoded' data */
int datalen; /* length of data */
+ bool data_alloc;
int nr_names; /* total number of struct members */
const char **names; /* struct member names */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 8f85a62e527..4c5cb5a473a 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -252,7 +252,7 @@ typedef struct SpaceOops {
struct BLI_mempool *treestore;
/* search stuff */
- char search_string[32];
+ char search_string[64];
struct TreeStoreElem search_tse;
short flag, outlinevis, storeflag, search_flags;
@@ -412,6 +412,8 @@ typedef enum eSpaceNla_Flag {
SNLA_NOSTRIPCURVES = (1 << 5),
/* don't perform realtime updates */
SNLA_NOREALTIMEUPDATES = (1 << 6),
+ /* don't show local strip marker indications */
+ SNLA_NOLOCALMARKERS = (1 << 7),
} eSpaceNla_Flag;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1c64522cd83..d338d279b72 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -284,7 +284,10 @@ typedef struct ThemeSpace {
char nodeclass_pattern[4], nodeclass_layout[4];
char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */
- char effect[4], transition[4], meta[4], text_strip[4], pad[4];
+ char effect[4], transition[4], meta[4], text_strip[4];
+
+ float keyframe_scale_fac; /* for dopesheet - scale factor for size of keyframes (i.e. height of channels) */
+
char editmesh_active[4];
char handle_vertex[4];
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 99ab29fbdcc..9135d7bab7d 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -196,7 +196,10 @@ int DNA_elem_array_size(const char *str)
void DNA_sdna_free(SDNA *sdna)
{
- MEM_freeN(sdna->data);
+ if (sdna->data_alloc) {
+ MEM_freeN((void *)sdna->data);
+ }
+
MEM_freeN((void *)sdna->names);
MEM_freeN(sdna->types);
MEM_freeN(sdna->structs);
@@ -549,15 +552,24 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
/**
* Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
*/
-SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap)
+SDNA *DNA_sdna_from_data(
+ const void *data, const int datalen,
+ bool do_endian_swap, bool data_alloc)
{
SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna");
sdna->lastfind = 0;
sdna->datalen = datalen;
- sdna->data = MEM_mallocN(datalen, "sdna_data");
- memcpy(sdna->data, data, datalen);
+ if (data_alloc) {
+ char *data_copy = MEM_mallocN(datalen, "sdna_data");
+ memcpy(data_copy, data, datalen);
+ sdna->data = data_copy;
+ }
+ else {
+ sdna->data = data;
+ }
+ sdna->data_alloc = data_alloc;
init_structDNA(sdna, do_endian_swap);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 6851f380cd8..983d3f659ef 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -274,11 +274,11 @@ StructRNA *rna_PropertyGroup_refine(PointerRNA *ptr)
return ptr->type;
}
-static ID *rna_ID_copy(ID *id)
+static ID *rna_ID_copy(ID *id, Main *bmain)
{
ID *newid;
- if (id_copy(id, &newid, false)) {
+ if (id_copy(bmain, id, &newid, false)) {
if (newid) id_us_min(newid);
return newid;
}
@@ -969,6 +969,7 @@ static void rna_def_ID(BlenderRNA *brna)
/* functions */
func = RNA_def_function(srna, "copy", "rna_ID_copy");
RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 0eaeabccd99..00b7df122ee 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1624,7 +1624,7 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
flag = prop->editable ? prop->editable(ptr) : prop->flag;
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
- (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION)));
+ (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION)));
}
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
@@ -1656,13 +1656,13 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
id = ptr->id.data;
- return (flag & PROP_EDITABLE) && (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION));
+ return (flag & PROP_EDITABLE) && (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION));
}
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
{
/* check that base ID-block can support animation data */
- if (!id_type_can_have_animdata(ptr->id.data))
+ if (!id_can_have_animdata(ptr->id.data))
return false;
prop = rna_ensure_property(prop);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 402361ccde1..4283ac78b30 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -308,6 +308,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ prop = RNA_def_property(srna, "use_datablock_sort", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADS_FLAG_NO_DB_SORT);
+ RNA_def_property_ui_text(prop, "Sort Datablocks",
+ "Alphabetically sorts datablocks - mainly objects in the scene "
+ "(disable to increase viewport speed)");
+ RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
/* Debug Filtering Settings */
prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS);
@@ -700,7 +708,8 @@ static void rna_def_action(BlenderRNA *brna)
prop = RNA_def_property(srna, "pose_markers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "markers", NULL);
RNA_def_property_struct_type(prop, "TimelineMarker");
- RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* T45689 - so that the list isn't greyed out; adding/removing is still banned though */
+ /* Use lib exception so the list isn't grayed out; adding/removing is still banned though, see T45689 */
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_ui_text(prop, "Pose Markers", "Markers specific to this action, for labeling poses");
rna_def_action_pose_markers(brna, prop);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 36e2b9b0572..bf2b091576e 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -532,7 +532,7 @@ BlenderRNA *RNA_create(void)
brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA");
- DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+ DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
BLI_listbase_clear(&DefRNA.structs);
DefRNA.error = 0;
DefRNA.preprocess = 1;
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 3043c5452c0..5fb581eb74a 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -72,6 +72,7 @@ EnumPropertyItem rna_enum_fmodifier_type_items[] = {
EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
{BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
{BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
+ {BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", VICO_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"},
{BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
{BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 010e65bdf4b..fb7ce951da1 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -127,7 +127,7 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_
}
else {
BKE_reportf(reports, RPT_ERROR,
- "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)",
+ "%s '%s' must have zero users to be removed, found %d (try with do_unlink=True parameter)",
BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id));
}
}
@@ -225,7 +225,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
id_us_min(&ob->id);
ob->data = data;
- test_object_materials(bmain, ob->data);
+ test_object_materials(ob, ob->data);
return ob;
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e5dc613a0cd..ffc78a1db97 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1500,6 +1500,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ /* Note, keep in sync with operator 'MESH_OT_decimate' */
+
StructRNA *srna;
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 95f258e95f4..bda9763201a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -6647,7 +6647,8 @@ static void def_cmp_translate(StructRNA *srna)
prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "relative", 1);
- RNA_def_property_ui_text(prop, "Relative", "Use relative (percent) values to define blur radius");
+ RNA_def_property_ui_text(prop, "Relative",
+ "Use relative (fraction of input image size) values to define translation");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "wrap_axis", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 9c16f53b0c7..e8efb202531 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -395,7 +395,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
id_us_plus(id);
ob->data = id;
- test_object_materials(G.main, id);
+ test_object_materials(ob, id);
if (GS(id->name) == ID_CU)
BKE_curve_type_test(ob);
@@ -715,10 +715,10 @@ static int rna_Object_active_material_editable(PointerRNA *ptr)
bool is_editable;
if ((ob->matbits == NULL) || (ob->actcol == 0) || ob->matbits[ob->actcol - 1]) {
- is_editable = (ob->id.lib == NULL);
+ is_editable = !ID_IS_LINKED_DATABLOCK(ob);
}
else {
- is_editable = ob->data ? (((ID *)ob->data)->lib == NULL) : false;
+ is_editable = ob->data ? !ID_IS_LINKED_DATABLOCK(ob->data) : false;
}
return is_editable ? PROP_EDITABLE : 0;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 1e2c0d95835..532f788619e 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -839,21 +839,12 @@ static int rna_RenderSettings_save_buffers_get(PointerRNA *ptr)
RenderData *rd = (RenderData *)ptr->data;
Scene *scene = (Scene *)ptr->id.data;
- if (rd->mode & R_BORDER)
- return 0;
- else if (!BKE_scene_use_new_shading_nodes(scene))
+ if (!BKE_scene_use_new_shading_nodes(scene))
return (rd->scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) != 0;
else
return (rd->scemode & R_EXR_TILE_FILE) != 0;
}
-static int rna_RenderSettings_full_sample_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
-
- return (rd->scemode & R_FULL_SAMPLE) && !(rd->mode & R_BORDER);
-}
-
static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -4362,6 +4353,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
"Use extra textures like normal or specular maps for GLSL rendering");
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
+ prop = RNA_def_property(srna, "use_glsl_environment_lighting", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_ENV_LIGHTING);
+ RNA_def_property_ui_text(prop, "GLSL Environment Lighting", "Use environment lighting for GLSL rendering");
+ RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
+
prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING);
RNA_def_property_ui_text(prop, "Use Material Caching",
@@ -5744,7 +5740,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_full_sample", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FULL_SAMPLE);
- RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_full_sample_get", NULL);
RNA_def_property_ui_text(prop, "Full Sample",
"Save for every anti-aliasing sample the entire RenderLayer results "
"(this solves anti-aliasing issues with compositing)");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 559d7e82076..04557e15fee 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3603,6 +3603,12 @@ static void rna_def_space_nla(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
+ prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS);
+ RNA_def_property_ui_text(prop, "Show Local Markers",
+ "Show action-local markers on the strips, useful when synchronising timing across strips");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOREALTIMEUPDATES);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 264dbd7fcc1..289019fddde 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2790,6 +2790,13 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Keyframe Border Selected", "Color of selected keyframe border");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "keyframe_scale_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "keyframe_scale_fac");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Keyframe Scale Factor", "Scale factor for adjusting the height of keyframes");
+ RNA_def_property_range(prop, 0.8f, 5.0f); /* Note: These limits prevent buttons overlapping (min), and excessive size... (max) */
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_userdef_update");
+
prop = RNA_def_property(srna, "summary", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_active");
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index f950ba75c42..7c1ef6b0d87 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -102,8 +102,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
}
#endif
-/* so camera mist limits redraw */
-static void rna_World_draw_mist_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
World *wo = ptr->id.data;
@@ -264,19 +263,19 @@ static void rna_def_lighting(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_environment_light", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ENV_LIGHT);
RNA_def_property_ui_text(prop, "Use Environment Lighting", "Add light coming from the environment");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "environment_energy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ao_env_energy");
RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Environment Color", "Defines the strength of environment light");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "environment_color", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "aocolor");
RNA_def_property_enum_items(prop, prop_color_items);
RNA_def_property_ui_text(prop, "Environment Color", "Defines where the color of the environment light comes from");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
/* indirect lighting */
prop = RNA_def_property(srna, "use_indirect_light", PROP_BOOLEAN, PROP_NONE);
@@ -405,27 +404,27 @@ static void rna_def_world_mist(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_MIST);
RNA_def_property_ui_text(prop, "Use Mist", "Occlude objects with the environment color as they are further away");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "misi");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Minimum", "Overall minimum intensity of the mist effect");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "miststa");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 10000, 10, 2);
RNA_def_property_ui_text(prop, "Start", "Starting distance of the mist, measured from the camera");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "mistdist");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 10000, 10, 2);
RNA_def_property_ui_text(prop, "Depth", "Distance over which the mist effect fades in");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "misthi");
@@ -437,7 +436,7 @@ static void rna_def_world_mist(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mistype");
RNA_def_property_enum_items(prop, falloff_items);
RNA_def_property_ui_text(prop, "Falloff", "Type of transition used to fade mist");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
}
void RNA_def_world(BlenderRNA *brna)
@@ -462,19 +461,19 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon");
/* RNA_def_property_update(prop, 0, "rna_World_update"); */
/* render-only uses this */
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "zenr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Zenith Color", "Color at the zenith");
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "ambient_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "ambr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
/* exp, range */
prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 1fcf4c5ec79..3f418fa16f3 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -222,7 +222,7 @@ static DerivedMesh *applyModifier_bmesh(
#ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
#endif
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create_ex(&allocsize, );
DM_to_bmesh_ex(dm_other, bm, true);
DM_to_bmesh_ex(dm, bm, true);
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 4046620592b..77fd84a2948 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -1,29 +1,29 @@
/*
-* ***** 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) 2015 by the Blender Foundation.
-* All rights reserved.
-*
-* Contributor(s): Jack Simpson,
-* Campbell Barton
-*
-* ***** END GPL LICENSE BLOCK *****
-*
-*/
+ * ***** 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) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Jack Simpson,
+ * Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
/** \file blender/modifiers/intern/MOD_correctivesmooth.c
* \ingroup modifiers
@@ -319,7 +319,7 @@ static void smooth_iter__length_weight(
/* fast-path */
for (i = 0; i < numVerts; i++) {
struct SmoothingData_Weighted *sd = &smooth_data[i];
- /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */
+ /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */
const float div = sd->edge_length_sum * vertex_edge_count[i];
if (div > eps) {
#if 0
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 9f1ec4de3d5..8ed623734be 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1745,7 +1745,9 @@ static BMesh *build_skin(SkinNode *skin_nodes,
int v;
so.smd = smd;
- so.bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ so.bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
so.mat_nr = 0;
/* BMESH_TODO: bumping up the stack level (see MOD_array.c) */
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index f70c29e793f..9eb7e4e83b6 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -141,9 +141,9 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver
* using the angle between the 2 faces as a weighting */
#if 0
add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
- normalize_v3(edge_normal);
-
- mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
+ normalize_v3_length(
+ edge_normal,
+ angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
#else
mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
#endif
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 01a219d1457..170fbbed7f1 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -221,9 +221,11 @@ static void updateDepsgraph(ModifierData *md,
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 0968d2aa5e0..af59f11ba15 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -378,12 +378,15 @@ static void updateDepsgraph(ModifierData *md,
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
if (wmd->proximity_ob_target != NULL) {
DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index fe21757d5c2..adadd4834d4 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -1,23 +1,23 @@
/*
-* ***** 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 *****
-*
-*/
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
/** \file blender/modifiers/intern/MOD_wireframe.c
* \ingroup modifiers
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index 8c873b57790..e992c0773c2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -23,8 +23,7 @@
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
-
-*/
+ */
#include "node_shader_util.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 0264abe451f..37439569f77 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -23,8 +23,7 @@
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
-
-*/
+ */
#include "node_shader_util.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
index 6edf6c2a0b4..b0b25a4878b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -33,6 +33,8 @@
#include "node_shader_util.h"
+#include "GPU_material.h"
+
/* **************** TEXTURE ******************** */
static bNodeSocketTemplate sh_node_texture_in[] = {
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */
@@ -121,9 +123,20 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
{
Tex *tex = (Tex *)node->id;
- if (tex && tex->type == TEX_IMAGE && tex->ima) {
- GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
- GPU_stack_link(mat, "texture_image", in, out, texlink);
+ if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) {
+ if (tex->type == TEX_IMAGE) {
+ GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
+ GPU_stack_link(mat, "texture_image", in, out, texlink);
+ }
+ else { /* TEX_ENVMAP */
+ if (!in[0].link)
+ in[0].link = GPU_uniform(in[0].vec);
+ if (!GPU_material_use_world_space_shading(mat))
+ GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link);
+ GPU_link(mat, "mtex_cube_map_refl_from_refldir",
+ GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link);
+ GPU_link(mat, "color_to_normal", out[1].link, &out[2].link);
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 7c5d1961849..eb1594688c7 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -53,17 +53,31 @@
#include "bmesh_py_api.h" /* own include */
PyDoc_STRVAR(bpy_bm_new_doc,
-".. method:: new()\n"
+".. method:: new(use_operators=True)\n"
"\n"
+" :arg use_operators: Support calling operators in :mod:`bmesh.ops` (uses some extra memory per vert/edge/face).\n"
+" :type use_operators: bool\n"
" :return: Return a new, empty BMesh.\n"
" :rtype: :class:`bmesh.types.BMesh`\n"
);
-static PyObject *bpy_bm_new(PyObject *UNUSED(self))
+static PyObject *bpy_bm_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"use_operators", NULL};
BMesh *bm;
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ bool use_operators = true;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|$O&:new", (char **)kwlist,
+ PyC_ParseBool, &use_operators))
+ {
+ return NULL;
+ }
+
+ bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = use_operators,}));
return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_NOP);
}
@@ -155,7 +169,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
}
static struct PyMethodDef BPy_BM_methods[] = {
- {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc},
+ {"new", (PyCFunction)bpy_bm_new, METH_VARARGS | METH_KEYWORDS, bpy_bm_new_doc},
{"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc},
{"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc},
{NULL, NULL, 0, NULL}
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 1dc70c3d288..551a66d1ed8 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -698,6 +698,12 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
BPY_BM_CHECK_OBJ(py_bm);
bm = py_bm->bm;
+ if (bm->use_toolflags == false) {
+ PyErr_SetString(PyExc_ValueError,
+ "bmesh created with 'use_operators=False'");
+ return NULL;
+ }
+
/* could complain about entering with exceptions... */
BMO_error_clear(bm);
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index fe4360d1e3b..1d951bae48b 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1824,7 +1824,7 @@ static PyObject *bpy_bmface_calc_tangent_edge(BPy_BMFace *self)
PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_pair_doc,
".. method:: calc_tangent_edge_pair()\n"
"\n"
-" Return face tangent based on the two longest disconected edges.\n"
+" Return face tangent based on the two longest disconnected edges.\n"
"\n"
" - Tris: Use the edge pair with the most similar lengths.\n"
" - Quads: Use the longest edge pair.\n"
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 4bd2e9d8d62..3ea10228ad4 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -983,7 +983,7 @@ static PyObject *Buffer_repr(Buffer *self)
switch (self->type) {
case GL_BYTE: typestr = "GL_BYTE"; break;
case GL_SHORT: typestr = "GL_SHORT"; break;
- case GL_INT: typestr = "GL_BYTE"; break;
+ case GL_INT: typestr = "GL_INT"; break;
case GL_FLOAT: typestr = "GL_FLOAT"; break;
case GL_DOUBLE: typestr = "GL_DOUBLE"; break;
default: typestr = "UNKNOWN"; break;
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 11af0836e1c..311f621e13b 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -901,8 +901,8 @@ static void bpy_module_free(void *UNUSED(mod))
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
- * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])
- */
+ * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])
+ */
const char *kwlist[] = {
"False", "None", "True",
"and", "as", "assert", "break",
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
index 19759bf3e97..17a872a0676 100644
--- a/source/blender/render/intern/include/pixelblending.h
+++ b/source/blender/render/intern/include/pixelblending.h
@@ -38,7 +38,7 @@
*/
void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w);
void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y);
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask);
void mask_array(unsigned int mask, float filt[3][3]);
/**
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index d080ddcc375..349f0fc6844 100644
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -125,6 +125,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
}
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
// raycast
res = RE_rayobject_intersect(obj->target, isec);
@@ -168,6 +171,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
}
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
return res;
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index af6ac4a8fbf..3dcde1f4bb1 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -2028,9 +2028,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* exception for tangent space baking */
if (me->mtpoly==NULL) {
need_orco= 1;
- need_tangent= 1;
}
- need_nmap_tangent_concrete = true;
+ need_tangent= 1;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index b1afb86e5af..d97e18d6511 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -52,6 +52,7 @@
#include "BKE_main.h"
#include "BKE_image.h" /* BKE_imbuf_write */
#include "BKE_texture.h"
+#include "BKE_scene.h"
/* this module */
#include "render_types.h"
@@ -737,21 +738,28 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
/* rotate to envmap space, if object is set */
copy_v3_v3(vec, texvec);
- if (env->object) mul_m3_v3(env->obimat, vec);
- else mul_mat3_m4_v3(R.viewinv, vec);
+ if (env->object) {
+ mul_m3_v3(env->obimat, vec);
+ if (osatex) {
+ mul_m3_v3(env->obimat, dxt);
+ mul_m3_v3(env->obimat, dyt);
+ }
+ }
+ else {
+ if (!BKE_scene_use_world_space_shading(R.scene)) {
+ // texvec is in view space
+ mul_mat3_m4_v3(R.viewinv, vec);
+ if (osatex) {
+ mul_mat3_m4_v3(R.viewinv, dxt);
+ mul_mat3_m4_v3(R.viewinv, dyt);
+ }
+ }
+ }
face = envcube_isect(env, vec, sco);
ibuf = env->cube[face];
if (osatex) {
- if (env->object) {
- mul_m3_v3(env->obimat, dxt);
- mul_m3_v3(env->obimat, dyt);
- }
- else {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
set_dxtdyt(dxts, dyts, dxt, dyt, face);
imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 8c6d9c5f951..fba5836ac32 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -864,8 +864,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
lvl, lt, uv[0], uv[1], NULL, n);
mul_v3_m3v3(vec, tangmat, n);
- normalize_v3(vec);
- mul_v3_fl(vec, 0.5);
+ normalize_v3_length(vec, 0.5);
add_v3_v3(vec, tmp);
if (ibuf->rect_float) {
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index d81d77dc161..100d87a037a 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -633,12 +633,6 @@ static int check_mode_full_sample(RenderData *rd)
#ifdef WITH_OPENEXR
if (scemode & R_FULL_SAMPLE)
scemode |= R_EXR_TILE_FILE; /* enable automatic */
-
- /* Until use_border is made compatible with save_buffers/full_sample, render without the later instead of not rendering at all.*/
- if (rd->mode & R_BORDER) {
- scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
- }
-
#else
/* can't do this without openexr support */
scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
@@ -727,6 +721,13 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.size = source->r.size;
}
+ /* disable border if it's a full render anyway */
+ if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f &&
+ re->r.border.ymin == 0.0f && re->r.border.ymax == 1.0f)
+ {
+ re->r.mode &= ~R_BORDER;
+ }
+
re_init_resolution(re, source, winx, winy, disprect);
if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) &&
@@ -1828,6 +1829,53 @@ static void render_result_disprect_to_full_resolution(Render *re)
re->recty = re->winy;
}
+static void render_result_uncrop(Render *re)
+{
+ /* when using border render with crop disabled, insert render result into
+ * full size with black pixels outside */
+ if (re->result && (re->r.mode & R_BORDER)) {
+ if ((re->r.mode & R_CROP) == 0) {
+ RenderResult *rres;
+
+ /* backup */
+ const rcti orig_disprect = re->disprect;
+ const int orig_rectx = re->rectx, orig_recty = re->recty;
+
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
+ /* sub-rect for merge call later on */
+ re->result->tilerect = re->disprect;
+
+ /* weak is: it chances disprect from border */
+ render_result_disprect_to_full_resolution(re);
+
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+
+ render_result_merge(rres, re->result);
+ render_result_free(re->result);
+ re->result = rres;
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay = render_get_active_layer(re, re->result);
+
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ re->display_init(re->dih, re->result);
+ re->display_update(re->duh, re->result, NULL);
+
+ /* restore the disprect from border */
+ re->disprect = orig_disprect;
+ re->rectx = orig_rectx;
+ re->recty = orig_recty;
+ }
+ else {
+ /* set offset (again) for use in compositor, disprect was manipulated. */
+ re->result->xof = 0;
+ re->result->yof = 0;
+ }
+ }
+}
+
/* main render routine, no compositing */
static void do_render_fields_blur_3d(Render *re)
{
@@ -1850,49 +1898,7 @@ static void do_render_fields_blur_3d(Render *re)
do_render_3d(re);
/* when border render, check if we have to insert it in black */
- if (re->result) {
- if (re->r.mode & R_BORDER) {
- if ((re->r.mode & R_CROP) == 0) {
- RenderResult *rres;
-
- /* backup */
- const rcti orig_disprect = re->disprect;
- const int orig_rectx = re->rectx, orig_recty = re->recty;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
-
- /* sub-rect for merge call later on */
- re->result->tilerect = re->disprect;
-
- /* weak is: it chances disprect from border */
- render_result_disprect_to_full_resolution(re);
-
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- render_result_merge(rres, re->result);
- render_result_free(re->result);
- re->result = rres;
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->display_init(re->dih, re->result);
- re->display_update(re->duh, re->result, NULL);
-
- /* restore the disprect from border */
- re->disprect = orig_disprect;
- re->rectx = orig_rectx;
- re->recty = orig_recty;
- }
- else {
- /* set offset (again) for use in compositor, disprect was manipulated. */
- re->result->xof = 0;
- re->result->yof = 0;
- }
- }
- }
+ render_result_uncrop(re);
}
@@ -2177,12 +2183,12 @@ static void init_freestyle(Render *re)
re->freestyle_bmain = BKE_main_new();
/* We use the same window manager for freestyle bmain as
- * real bmain uses. This is needed because freestyle's
- * bmain could be used to tag scenes for update, which
- * implies call of ED_render_scene_update in some cases
- * and that function requires proper window manager
- * to present (sergey)
- */
+ * real bmain uses. This is needed because freestyle's
+ * bmain could be used to tag scenes for update, which
+ * implies call of ED_render_scene_update in some cases
+ * and that function requires proper window manager
+ * to present (sergey)
+ */
re->freestyle_bmain->wm = re->main->wm;
FRS_init_stroke_renderer(re);
@@ -2267,7 +2273,7 @@ static void free_all_freestyle_renders(void)
if (freestyle_render) {
freestyle_scene = freestyle_render->scene;
RE_FreeRender(freestyle_render);
- BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false);
+ BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false, false);
BKE_libblock_free(re1->freestyle_bmain, freestyle_scene);
}
}
@@ -2291,6 +2297,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
{
ListBase *rectfs;
RenderView *rv;
+ rcti filter_mask = re->disprect;
float *rectf, filt[3][3];
int x, y, sample;
int nr, numviews;
@@ -2316,7 +2323,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
/* we accumulate in here */
- rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
+ rv->rectf = MEM_mapallocN(re->result->rectx * re->result->recty * sizeof(float) * 4, "fullsample rgba");
BLI_addtail(rectfs, rv);
}
@@ -2346,6 +2353,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
composite_freestyle_renders(re1, sample);
#endif
BLI_rw_mutex_unlock(&re->resultmutex);
+ render_result_uncrop(re1);
}
ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */
}
@@ -2372,17 +2380,17 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
mask = (1 << sample);
mask_array(mask, filt);
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
- float *col = rres.rectf + 4 * y * re->rectx;
+ for (y = 0; y < re->result->recty; y++) {
+ float *rf = rectf + 4 * y * re->result->rectx;
+ float *col = rres.rectf + 4 * y * re->result->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
+ for (x = 0; x < re->result->rectx; x++, rf += 4, col += 4) {
/* clamping to 1.0 is needed for correct AA */
CLAMP(col[0], 0.0f, 1.0f);
CLAMP(col[1], 0.0f, 1.0f);
CLAMP(col[2], 0.0f, 1.0f);
- add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ add_filt_fmask_coord(filt, col, rf, re->result->rectx, x, y, &filter_mask);
}
}
@@ -2402,10 +2410,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
+ for (y = 0; y < re->result->recty; y++) {
+ float *rf = rectf + 4 * y * re->result->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4) {
+ for (x = 0; x < re->result->rectx; x++, rf += 4) {
rf[0] = MAX2(rf[0], 0.0f);
rf[1] = MAX2(rf[1], 0.0f);
rf[2] = MAX2(rf[2], 0.0f);
@@ -3821,6 +3829,8 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
success = render_result_exr_file_cache_read(re);
BLI_rw_mutex_unlock(&re->resultmutex);
+ render_result_uncrop(re);
+
return success;
}
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
index 32fb196e1f3..fc79786e5c7 100644
--- a/source/blender/render/intern/source/pixelblending.c
+++ b/source/blender/render/intern/source/pixelblending.c
@@ -240,7 +240,7 @@ void mask_array(unsigned int mask, float filt[3][3])
* </pre>
*/
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y)
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask)
{
float *fpoin[3][3];
float val, r, g, b, al, lfilt[3][3];
@@ -252,9 +252,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
memcpy(lfilt, filt, sizeof(lfilt));
- fpoin[0][1] = rowbuf - 4 * row_w;
+ fpoin[0][1] = rowbuf - 4 * row_stride;
fpoin[1][1] = rowbuf;
- fpoin[2][1] = rowbuf + 4 * row_w;
+ fpoin[2][1] = rowbuf + 4 * row_stride;
fpoin[0][0] = fpoin[0][1] - 4;
fpoin[1][0] = fpoin[1][1] - 4;
@@ -264,7 +264,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
fpoin[1][2] = fpoin[1][1] + 4;
fpoin[2][2] = fpoin[2][1] + 4;
- if (y == 0) {
+ /* limit filtering to withing a mask for border rendering, so pixels don't
+ * leak outside of the border */
+ if (y <= mask->ymin) {
fpoin[0][0] = fpoin[1][0];
fpoin[0][1] = fpoin[1][1];
fpoin[0][2] = fpoin[1][2];
@@ -273,7 +275,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[0][1] = filt[2][1];
lfilt[0][2] = filt[2][2];
}
- else if (y == col_h - 1) {
+ else if (y >= mask->ymax - 1) {
fpoin[2][0] = fpoin[1][0];
fpoin[2][1] = fpoin[1][1];
fpoin[2][2] = fpoin[1][2];
@@ -283,7 +285,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[2][2] = filt[0][2];
}
- if (x == 0) {
+ if (x <= mask->xmin) {
fpoin[2][0] = fpoin[2][1];
fpoin[1][0] = fpoin[1][1];
fpoin[0][0] = fpoin[0][1];
@@ -292,7 +294,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[1][0] = filt[1][2];
lfilt[0][0] = filt[0][2];
}
- else if (x == row_w - 1) {
+ else if (x >= mask->xmax - 1) {
fpoin[2][2] = fpoin[2][1];
fpoin[1][2] = fpoin[1][1];
fpoin[0][2] = fpoin[0][1];
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 530ebc084be..513cfa6df7d 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1720,6 +1720,21 @@ static void texco_mapping(ShadeInput *shi, Tex *tex, MTex *mtex,
}
else dxt[2]= dyt[2] = 0.f;
}
+
+ if (mtex->tex->type == TEX_ENVMAP) {
+ EnvMap *env = tex->env;
+ if (!env->object) {
+ // env->object is a view point for envmap rendering
+ // if it's not set, return the result depending on the world_space_shading flag
+ if (BKE_scene_use_world_space_shading(R.scene)) {
+ mul_mat3_m4_v3(R.viewinv, texvec);
+ if (shi->osatex) {
+ mul_mat3_m4_v3(R.viewinv, dxt);
+ mul_mat3_m4_v3(R.viewinv, dyt);
+ }
+ }
+ }
+ }
}
}
@@ -2480,8 +2495,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
/* can be optimized... (ton) */
mul_mat3_m4_v3(shi->obr->ob->obmat, texres.nor);
mul_mat3_m4_v3(re->viewmat, texres.nor);
- normalize_v3(texres.nor);
- mul_v3_fl(texres.nor, len);
+ normalize_v3_length(texres.nor, len);
}
}
}
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 72b26cc6207..a11733c060b 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1787,7 +1787,17 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
}
/* UV Editor */
else if (STRPREFIX(opname, "UV_OT")) {
- km = WM_keymap_find_all(C, "UV Editor", 0, 0);
+ /* Hack to allow using UV unwrapping ops from 3DView/editmode.
+ * Mesh keymap is probably not ideal, but best place I could find to put those. */
+ if (sl->spacetype == SPACE_VIEW3D) {
+ km = WM_keymap_find_all(C, "Mesh", 0, 0);
+ if (km && km->poll && !km->poll((bContext *)C)) {
+ km = NULL;
+ }
+ }
+ if (!km) {
+ km = WM_keymap_find_all(C, "UV Editor", 0, 0);
+ }
}
/* Node Editor */
else if (STRPREFIX(opname, "NODE_OT")) {
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 8968c2a4543..78273615602 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2851,8 +2851,8 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
/* *********************** radial control ****************** */
-#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize)
-#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
+#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200)
+#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
#define WM_RADIAL_MAX_STR 10
@@ -2929,7 +2929,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
case PROP_NONE:
case PROP_DISTANCE:
case PROP_PIXEL:
- d[0] = rc->initial_value * U.pixelsize;
+ d[0] = rc->initial_value;
break;
case PROP_PERCENTAGE:
d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -3055,8 +3055,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
case PROP_NONE:
case PROP_DISTANCE:
case PROP_PIXEL:
- r1 = rc->current_value * U.pixelsize;
- r2 = rc->initial_value * U.pixelsize;
+ r1 = rc->current_value;
+ r2 = rc->initial_value;
tex_radius = r1;
alpha = 0.75;
break;
@@ -3538,7 +3538,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
case PROP_PIXEL:
new_value = dist;
if (snap) new_value = ((int)new_value + 5) / 10 * 10;
- new_value /= U.pixelsize;
break;
case PROP_PERCENTAGE:
new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f;
@@ -3884,7 +3883,7 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
/* Only preview non-library datablocks, lib ones do not pertain to this .blend file!
* Same goes for ID with no user. */
- if (!id->lib && (id->us != 0)) {
+ if (!ID_IS_LINKED_DATABLOCK(id) && (id->us != 0)) {
UI_id_icon_render(C, scene, id, false, false);
UI_id_icon_render(C, scene, id, true, false);
}
@@ -4469,7 +4468,7 @@ static EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(pt
int i = 0;
for (; id; id = id->next) {
- if (local == false || id->lib == NULL) {
+ if (local == false || !ID_IS_LINKED_DATABLOCK(id)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 91d03da005e..4e8dd6f9fd3 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -172,18 +172,28 @@ if(WITH_BUILDINFO)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
- # XXX, "_buildinfo.h" is used twice here,
+ # XXX, ${buildinfo_h_fake} is used here,
# because we rely on that file being detected as missing
# every build so that the real header "buildinfo.h" is updated.
#
# Keep this until we find a better way to resolve!
+ set(buildinfo_h_real "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h")
+ set(buildinfo_h_fake "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h_fake")
+
+ if(EXISTS ${buildinfo_h_fake})
+ message(FATAL_ERROR "File \"${buildinfo_h_fake}\" found, this should never be created, remove!")
+ endif()
+
# a custom target that is always built
add_custom_target(buildinfo ALL
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h)
+ DEPENDS ${buildinfo_h_fake})
# creates buildinfo.h using cmake script
- add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h
+ add_custom_command(
+ OUTPUT
+ ${buildinfo_h_fake} # ensure we always run
+ ${buildinfo_h_real}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
# overrides only used when non-empty strings
@@ -192,10 +202,14 @@ if(WITH_BUILDINFO)
-P ${CMAKE_SOURCE_DIR}/build_files/cmake/buildinfo.cmake)
# buildinfo.h is a generated file
- set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h
+ set_source_files_properties(
+ ${buildinfo_h_real}
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
+ unset(buildinfo_h_real)
+ unset(buildinfo_h_fake)
+
# add deps below, after adding blender
# -------------- done with header values.
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index a1819a8dc92..a5af525e13a 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -233,8 +233,8 @@ BL_ArmatureObject::BL_ArmatureObject(
m_lastapplyframe(0.0)
{
m_origObjArma = armature; // Keep a copy of the original armature so we can fix drivers later
- m_objArma = BKE_object_copy(armature);
- m_objArma->data = BKE_armature_copy((bArmature *)armature->data);
+ m_objArma = BKE_object_copy(G.main, armature);
+ m_objArma->data = BKE_armature_copy(G.main, (bArmature *)armature->data);
// During object replication ob->data is increase, we decrease it now because we get a copy.
id_us_min(&((bArmature *)m_origObjArma->data)->id);
m_pose = m_objArma->pose;
@@ -433,8 +433,8 @@ void BL_ArmatureObject::ProcessReplica()
KX_GameObject::ProcessReplica();
bArmature* tmp = (bArmature*)m_objArma->data;
- m_objArma = BKE_object_copy(m_objArma);
- m_objArma->data = BKE_armature_copy(tmp);
+ m_objArma = BKE_object_copy(G.main, m_objArma);
+ m_objArma->data = BKE_armature_copy(G.main, tmp);
m_pose = m_objArma->pose;
}
diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp
index 5e31dabfab1..94256a64d75 100644
--- a/source/gameengine/Converter/BL_ShapeDeformer.cpp
+++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp
@@ -75,7 +75,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
m_useShapeDrivers(false),
m_lastShapeUpdate(-1)
{
- m_key = BKE_key_copy(m_bmesh->key);
+ m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL;
};
/* this second constructor is needed for making a mesh deformable on the fly. */
@@ -91,7 +91,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
m_useShapeDrivers(false),
m_lastShapeUpdate(-1)
{
- m_key = BKE_key_copy(m_bmesh->key);
+ m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL;
};
BL_ShapeDeformer::~BL_ShapeDeformer()
@@ -117,7 +117,7 @@ void BL_ShapeDeformer::ProcessReplica()
BL_SkinDeformer::ProcessReplica();
m_lastShapeUpdate = -1;
- m_key = BKE_key_copy(m_key);
+ m_key = m_key ? BKE_key_copy(G.main, m_key) : NULL;
}
bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent)
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index b97d0b2a85d..08b569fa4c2 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -1425,7 +1425,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
#ifdef DEBUG
printf("Mesh has a user \"%s\"\n", name);
#endif
- me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me);
+ me = (ID*)BKE_mesh_copy(from_maggie, (Mesh*)me);
id_us_min(me);
}
BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
@@ -1447,12 +1447,12 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
/* if its tagged its a replaced material */
if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) {
Material *mat_old = mesh->mat[i];
- Material *mat_new = BKE_material_copy(mat_old);
+ Material *mat_new = BKE_material_copy(from_maggie, mat_old);
mat_new->id.tag |= LIB_TAG_DOIT;
id_us_min(&mat_old->id);
- BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
+ BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
BLI_addtail(&maggie->mat, mat_new);
mesh->mat[i] = mat_new;
diff --git a/source/gameengine/Expressions/intern/IntValue.cpp b/source/gameengine/Expressions/intern/IntValue.cpp
index 25aff5b32ab..7b2e841f13f 100644
--- a/source/gameengine/Expressions/intern/IntValue.cpp
+++ b/source/gameengine/Expressions/intern/IntValue.cpp
@@ -3,17 +3,17 @@
*/
// IntValue.cpp: implementation of the CIntValue class.
/*
-* Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
-*
-* Permission to use, copy, modify, distribute and sell this software
-* and its documentation for any purpose is hereby granted without fee,
-* provided that the above copyright notice appear in all copies and
-* that both that copyright notice and this permission notice appear
-* in supporting documentation. Erwin Coumans makes no
-* representations about the suitability of this software for any
-* purpose. It is provided "as is" without express or implied warranty.
-*
-*/
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
#include <stdio.h>
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 1b52c61b816..e697306e038 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -633,7 +633,9 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
if (!m_rasterizer)
goto initFailed;
-
+
+ m_rasterizer->PrintHardwareInfo();
+
// create the inputdevices
m_keyboard = new GPG_KeyboardDevice();
if (!m_keyboard)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index 0ea3a3e62eb..9c3f94f1918 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -46,8 +46,8 @@
#include "KX_PyConstraintBinding.h" // for PHY_SetActiveEnvironment
/**********************************
-* Begin Blender include block
-**********************************/
+ * Begin Blender include block
+ **********************************/
#ifdef __cplusplus
extern "C"
{
@@ -103,8 +103,8 @@ extern char datatoc_bmonofont_ttf[];
#include "GPU_draw.h"
/**********************************
-* End Blender include block
-**********************************/
+ * End Blender include block
+ **********************************/
#include "BL_System.h"
#include "GPG_Application.h"
@@ -463,8 +463,8 @@ int main(
/* Win32 Unicode Args */
/* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
- * (it depends on the args passed in, which is what we're getting here!)
- */
+ * (it depends on the args passed in, which is what we're getting here!)
+ */
{
wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
argv = (char**)malloc(argc * sizeof(char *));
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index 45946f30827..7175eb877dd 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -161,7 +161,7 @@ bool BL_Action::Play(const char* name,
BKE_libblock_free(G.main, m_tmpaction);
m_tmpaction = NULL;
}
- m_tmpaction = BKE_action_copy(m_action);
+ m_tmpaction = BKE_action_copy(G.main, m_action);
// First get rid of any old controllers
ClearControllerList();
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index 7138409a7e8..831e7346df7 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -542,14 +542,14 @@ protected:
CcdPhysicsController (const CcdConstructionInfo& ci);
/**
- * Delete the current Bullet shape used in the rigid body.
- */
+ * Delete the current Bullet shape used in the rigid body.
+ */
bool DeleteControllerShape();
/**
- * Delete the old Bullet shape and set the new Bullet shape : newShape
- * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape
- */
+ * Delete the old Bullet shape and set the new Bullet shape : newShape
+ * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape
+ */
bool ReplaceControllerShape(btCollisionShape *newShape);
virtual ~CcdPhysicsController();
diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h
index e5f3dc43e5f..d61a31504b8 100644
--- a/source/gameengine/Rasterizer/RAS_IOffScreen.h
+++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/Rasterizer/RAS_ISync.h b/source/gameengine/Rasterizer/RAS_ISync.h
index b9987dc1cad..7e34172c2a3 100644
--- a/source/gameengine/Rasterizer/RAS_ISync.h
+++ b/source/gameengine/Rasterizer/RAS_ISync.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
index 26ece47d8b3..e589bffcaf1 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
index 94d0d4aa105..3f6845f1e21 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index fcb11ce2355..3f82c513f7d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -141,8 +141,6 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE
glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights);
if (m_numgllights < 8)
m_numgllights = 8;
-
- PrintHardwareInfo();
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
index ebb4a9a3ca1..d54b3232067 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
index 9b6340b04ac..4ba96903856 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp
index 0506756ef2d..fa8ab8c641c 100644
--- a/source/gameengine/VideoTexture/DeckLink.cpp
+++ b/source/gameengine/VideoTexture/DeckLink.cpp
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h
index 1c96af7b4bc..4528fe7cec0 100644
--- a/source/gameengine/VideoTexture/DeckLink.h
+++ b/source/gameengine/VideoTexture/DeckLink.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
index c8d3c28c551..4f5e34896fc 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.cpp
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h
index be81f63d93c..50099d2ead4 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.h
+++ b/source/gameengine/VideoTexture/VideoDeckLink.h
@@ -15,12 +15,12 @@
* 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) 2015, Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Blender Foundation.
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
*
* ***** END GPL LICENSE BLOCK *****
*/
diff --git a/tests/gtests/bmesh/bmesh_core_test.cc b/tests/gtests/bmesh/bmesh_core_test.cc
index 0cbb6ca343e..f386abc0b2b 100644
--- a/tests/gtests/bmesh/bmesh_core_test.cc
+++ b/tests/gtests/bmesh/bmesh_core_test.cc
@@ -9,7 +9,9 @@ TEST(bmesh_core, BMVertCreate) {
BMVert *bv1, *bv2, *bv3;
const float co1[3] = {1.0f, 2.0f, 0.0f};
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BMeshCreateParams bm_params;
+ bm_params.use_toolflags = true;
+ bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params);
EXPECT_EQ(0, bm->totvert);
/* make a custom layer so we can see if it is copied properly */
BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLT);
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index fb9e63aa222..e1b5e2d1d23 100755
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -70,7 +70,8 @@ def verify_output(filepath):
os.remove(failed_image)
return True
except subprocess.CalledProcessError as e:
- shutil.copy(TEMP_FILE, failed_image)
+ if e.returncode != 1:
+ shutil.copy(TEMP_FILE, failed_image)
if VERBOSE:
print(e.output.decode("utf-8"))
return e.returncode == 1