Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorDalai Felinto <dfelinto@gmail.com>2016-10-20 19:03:44 +0300
committerDalai Felinto <dfelinto@gmail.com>2016-10-20 20:00:49 +0300
commit418b24551e1b8a4458deceedca945a631f0684ac (patch)
treecfb1f42ff1eb58e36f714132d3ed623c18bfc6f7 /source
parenta84794b39960029a61d7c2c79e4ad7e2fda06bb7 (diff)
parent9269574089a742130f02c0a1184a19d94f0e665d (diff)
Merge commit '9269574089a742130f02c0a1184a19d94f0e665d' into pbr-online
Merge conflicts fixes include fix on ob->reflectionplane for write and read, and a few manual fixes to account for the ID remap changes Conflicts: source/blender/blenkernel/intern/object.c source/blender/blenkernel/intern/world.c source/blender/blenloader/intern/writefile.c source/blender/editors/space_view3d/view3d_draw.c source/blender/gpu/GPU_draw.h source/blender/gpu/intern/gpu_draw.c source/blender/gpu/intern/gpu_material.c source/blender/gpu/intern/gpu_texture.c source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c14
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h2
-rw-r--r--source/blender/blenkernel/BKE_blender.h5
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h32
-rw-r--r--source/blender/blenkernel/BKE_curve.h11
-rw-r--r--source/blender/blenkernel/BKE_displist.h14
-rw-r--r--source/blender/blenkernel/BKE_group.h1
-rw-r--r--source/blender/blenkernel/BKE_library.h18
-rw-r--r--source/blender/blenkernel/BKE_library_idmap.h50
-rw-r--r--source/blender/blenkernel/BKE_library_query.h5
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h78
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h2
-rw-r--r--source/blender/blenkernel/BKE_mask.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h10
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_particle.h15
-rw-r--r--source/blender/blenkernel/BKE_sca.h1
-rw-r--r--source/blender/blenkernel/BKE_scene.h4
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/BKE_world.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt7
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c45
-rw-r--r--source/blender/blenkernel/intern/action.c15
-rw-r--r--source/blender/blenkernel/intern/anim.c10
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c18
-rw-r--r--source/blender/blenkernel/intern/armature.c32
-rw-r--r--source/blender/blenkernel/intern/blender.c53
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c14
-rw-r--r--source/blender/blenkernel/intern/brush.c29
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c123
-rw-r--r--source/blender/blenkernel/intern/camera.c3
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c29
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c9
-rw-r--r--source/blender/blenkernel/intern/curve.c118
-rw-r--r--source/blender/blenkernel/intern/customdata.c2
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c4
-rw-r--r--source/blender/blenkernel/intern/displist.c14
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c202
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c33
-rw-r--r--source/blender/blenkernel/intern/effect.c5
-rw-r--r--source/blender/blenkernel/intern/font.c78
-rw-r--r--source/blender/blenkernel/intern/gpencil.c9
-rw-r--r--source/blender/blenkernel/intern/group.c66
-rw-r--r--source/blender/blenkernel/intern/idcode.c19
-rw-r--r--source/blender/blenkernel/intern/image.c15
-rw-r--r--source/blender/blenkernel/intern/key.c6
-rw-r--r--source/blender/blenkernel/intern/lamp.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c23
-rw-r--r--source/blender/blenkernel/intern/library.c270
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c176
-rw-r--r--source/blender/blenkernel/intern/library_query.c191
-rw-r--r--source/blender/blenkernel/intern/library_remap.c776
-rw-r--r--source/blender/blenkernel/intern/linestyle.c42
-rw-r--r--source/blender/blenkernel/intern/mask.c59
-rw-r--r--source/blender/blenkernel/intern/material.c42
-rw-r--r--source/blender/blenkernel/intern/mball.c23
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh.c54
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c13
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c8
-rw-r--r--source/blender/blenkernel/intern/movieclip.c77
-rw-r--r--source/blender/blenkernel/intern/node.c58
-rw-r--r--source/blender/blenkernel/intern/object.c488
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c2
-rw-r--r--source/blender/blenkernel/intern/object_update.c11
-rw-r--r--source/blender/blenkernel/intern/paint.c11
-rw-r--r--source/blender/blenkernel/intern/particle.c57
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c43
-rw-r--r--source/blender/blenkernel/intern/particle_system.c38
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c124
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/sca.c71
-rw-r--r--source/blender/blenkernel/intern/scene.c93
-rw-r--r--source/blender/blenkernel/intern/screen.c17
-rw-r--r--source/blender/blenkernel/intern/sequencer.c4
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c54
-rw-r--r--source/blender/blenkernel/intern/softbody.c2
-rw-r--r--source/blender/blenkernel/intern/sound.c15
-rw-r--r--source/blender/blenkernel/intern/speaker.c5
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c3
-rw-r--r--source/blender/blenkernel/intern/text.c194
-rw-r--r--source/blender/blenkernel/intern/texture.c37
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c2
-rw-r--r--source/blender/blenkernel/intern/world.c33
-rw-r--r--source/blender/blenlib/BLI_array_store_utils.h50
-rw-r--r--source/blender/blenlib/BLI_array_utils.h4
-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_matrix.h8
-rw-r--r--source/blender/blenlib/BLI_math_vector.h20
-rw-r--r--source/blender/blenlib/BLI_quadric.h7
-rw-r--r--source/blender/blenlib/BLI_rand.h1
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c4
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c416
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c2
-rw-r--r--source/blender/blenlib/intern/array_store.c8
-rw-r--r--source/blender/blenlib/intern/array_store_utils.c103
-rw-r--r--source/blender/blenlib/intern/array_utils.c20
-rw-r--r--source/blender/blenlib/intern/hash_md5.c2
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c4
-rw-r--r--source/blender/blenlib/intern/math_geom.c67
-rw-r--r--source/blender/blenlib/intern/math_matrix.c17
-rw-r--r--source/blender/blenlib/intern/math_vector.c117
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c7
-rw-r--r--source/blender/blenlib/intern/path_util.c2
-rw-r--r--source/blender/blenlib/intern/quadric.c86
-rw-r--r--source/blender/blenlib/intern/rand.c40
-rw-r--r--source/blender/blenlib/intern/storage.c2
-rw-r--r--source/blender/blenlib/intern/task.c5
-rw-r--r--source/blender/blenloader/BLO_readfile.h3
-rw-r--r--source/blender/blenloader/CMakeLists.txt7
-rw-r--r--source/blender/blenloader/intern/readblenentry.c9
-rw-r--r--source/blender/blenloader/intern/readfile.c503
-rw-r--r--source/blender/blenloader/intern/readfile.h6
-rw-r--r--source/blender/blenloader/intern/versioning_270.c16
-rw-r--r--source/blender/blenloader/intern/writefile.c3177
-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.c243
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c221
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h3
-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.c19
-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.c81
-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.c73
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c68
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c60
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c58
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c50
-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_collapse.c274
-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/bmesh/tools/bmesh_intersect.c145
-rw-r--r--source/blender/collada/MeshImporter.cpp28
-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/operations/COM_ImageOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc44
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc103
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc11
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h11
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/drivers.c8
-rw-r--r--source/blender/editors/animation/keyframes_edit.c74
-rw-r--r--source/blender/editors/animation/keyframing.c5
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/curve/editfont.c58
-rw-r--r--source/blender/editors/curve/editfont_undo.c311
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c46
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c4
-rw-r--r--source/blender/editors/include/BIF_glutil.h1
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h6
-rw-r--r--source/blender/editors/include/ED_fileselect.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h34
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_outliner.h6
-rw-r--r--source/blender/editors/include/ED_physics.h8
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h2
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h12
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface.c10
-rw-r--r--source/blender/editors/interface/interface_draw.c21
-rw-r--r--source/blender/editors/interface/interface_handlers.c132
-rw-r--r--source/blender/editors/interface/interface_icons.c11
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_style.c12
-rw-r--r--source/blender/editors/interface/interface_templates.c17
-rw-r--r--source/blender/editors/interface/interface_widgets.c12
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/mask/mask_draw.c18
-rw-r--r--source/blender/editors/mask/mask_editaction.c30
-rw-r--r--source/blender/editors/mesh/editface.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c236
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c10
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c91
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c25
-rw-r--r--source/blender/editors/object/object_add.c35
-rw-r--r--source/blender/editors/object/object_constraint.c76
-rw-r--r--source/blender/editors/object/object_edit.c1
-rw-r--r--source/blender/editors/object/object_group.c4
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c8
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c15
-rw-r--r--source/blender/editors/physics/rigidbody_object.c21
-rw-r--r--source/blender/editors/render/render_preview.c8
-rw-r--r--source/blender/editors/screen/glutil.c13
-rw-r--r--source/blender/editors/screen/screen_edit.c5
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c240
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c14
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c138
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_intern.h2
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/action_select.c259
-rw-r--r--source/blender/editors/space_action/space_action.c17
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c30
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c58
-rw-r--r--source/blender/editors/space_clip/clip_draw.c52
-rw-r--r--source/blender/editors/space_clip/space_clip.c21
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/file_utils.c17
-rw-r--r--source/blender/editors/space_file/filelist.c16
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c7
-rw-r--r--source/blender/editors/space_graph/graph_select.c83
-rw-r--r--source/blender/editors/space_graph/space_graph.c62
-rw-r--r--source/blender/editors/space_image/image_ops.c2
-rw-r--r--source/blender/editors/space_image/space_image.c30
-rw-r--r--source/blender/editors/space_logic/space_logic.c21
-rw-r--r--source/blender/editors/space_nla/space_nla.c17
-rw-r--r--source/blender/editors/space_node/node_edit.c28
-rw-r--r--source/blender/editors/space_node/space_node.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c23
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c470
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h66
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c278
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c36
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c20
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c111
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c19
-rw-r--r--source/blender/editors/space_text/space_text.c18
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c25
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c42
-rw-r--r--source/blender/editors/space_view3d/drawobject.c82
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c63
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c19
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c47
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c4
-rw-r--r--source/blender/editors/transform/transform.c26
-rw-r--r--source/blender/editors/transform/transform.h4
-rw-r--r--source/blender/editors/transform/transform_conversions.c62
-rw-r--r--source/blender/editors/transform/transform_ops.c5
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c22
-rw-r--r--source/blender/editors/transform/transform_snap_object.c922
-rw-r--r--source/blender/editors/util/ed_util.c19
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c9
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c14
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.h14
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsNoise.cpp2
-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/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/system/PythonInterpreter.h3
-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_basic_shader.h37
-rw-r--r--source/blender/gpu/GPU_buffers.h2
-rw-r--r--source/blender/gpu/GPU_draw.h25
-rw-r--r--source/blender/gpu/GPU_material.h1
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c98
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c29
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c6
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c5
-rw-r--r--source/blender/gpu/intern/gpu_draw.c176
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c4
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c1
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c3
-rw-r--r--source/blender/gpu/intern/gpu_material.c11
-rw-r--r--source/blender/gpu/intern/gpu_shader.c1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex_world.glsl6
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c7
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp4
-rw-r--r--source/blender/imbuf/intern/thumbs.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h5
-rw-r--r--source/blender/makesdna/DNA_camera_types.h4
-rw-r--r--source/blender/makesdna/DNA_curve_types.h20
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h2
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt21
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c52
-rw-r--r--source/blender/makesdna/intern/makesdna.c53
-rw-r--r--source/blender/makesrna/RNA_types.h5
-rw-r--r--source/blender/makesrna/intern/makesrna.c6
-rw-r--r--source/blender/makesrna/intern/rna_ID.c19
-rw-r--r--source/blender/makesrna/intern/rna_access.c2
-rw-r--r--source/blender/makesrna/intern/rna_camera.c6
-rw-r--r--source/blender/makesrna/intern/rna_curve.c34
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c441
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c11
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c21
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_particle.c20
-rw-r--r--source/blender/makesrna/intern/rna_pose.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c8
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c20
-rw-r--r--source/blender/makesrna/intern/rna_wm.c12
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c50
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c27
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c6
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c38
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c149
-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_geom.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c43
-rw-r--r--source/blender/physics/intern/implicit_blender.c7
-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.c80
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_operator.c5
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/rayintersection.h5
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp149
-rw-r--r--source/blender/render/intern/source/convertblender.c22
-rw-r--r--source/blender/render/intern/source/pipeline.c16
-rw-r--r--source/blender/render/intern/source/pointdensity.c2
-rw-r--r--source/blender/render/intern/source/render_texture.c3
-rw-r--r--source/blender/render/intern/source/shadeinput.c1
-rw-r--r--source/blender/windowmanager/WM_api.h8
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c7
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c9
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c402
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c33
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c16
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c13
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c144
-rw-r--r--source/blender/windowmanager/wm_event_types.h7
-rw-r--r--source/blender/windowmanager/wm_files.h3
-rw-r--r--source/blender/windowmanager/wm_subwindow.h2
-rw-r--r--source/blenderplayer/CMakeLists.txt8
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c6
-rw-r--r--source/creator/CMakeLists.txt26
-rw-r--r--source/creator/creator.c56
-rw-r--r--source/creator/creator_args.c13
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp1
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp2
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp3
-rw-r--r--source/gameengine/Expressions/EXP_PyObjectPlus.h18
-rw-r--r--source/gameengine/Expressions/intern/IntValue.cpp22
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp4
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp16
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.h6
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp24
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp156
-rw-r--r--source/gameengine/Ketsji/BL_Shader.h4
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp32
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h20
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp178
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h7
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp15
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp8
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h12
-rw-r--r--source/gameengine/Physics/common/PHY_ICharacter.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.h2
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt2
-rw-r--r--source/gameengine/Rasterizer/RAS_IOffScreen.h84
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h16
-rw-r--r--source/gameengine/Rasterizer/RAS_ISync.h48
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp347
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h65
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp43
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h11
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp82
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h50
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h2
-rw-r--r--source/gameengine/VideoTexture/CMakeLists.txt13
-rw-r--r--source/gameengine/VideoTexture/Common.h3
-rw-r--r--source/gameengine/VideoTexture/DeckLink.cpp813
-rw-r--r--source/gameengine/VideoTexture/DeckLink.h86
-rw-r--r--source/gameengine/VideoTexture/Exception.cpp15
-rw-r--r--source/gameengine/VideoTexture/Exception.h18
-rw-r--r--source/gameengine/VideoTexture/FilterBase.h7
-rw-r--r--source/gameengine/VideoTexture/FilterSource.h24
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp99
-rw-r--r--source/gameengine/VideoTexture/ImageBase.h10
-rw-r--r--source/gameengine/VideoTexture/ImageMix.cpp2
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp200
-rw-r--r--source/gameengine/VideoTexture/ImageRender.h28
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp99
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.h11
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp7
-rw-r--r--source/gameengine/VideoTexture/VideoBase.cpp47
-rw-r--r--source/gameengine/VideoTexture/VideoBase.h2
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp1228
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.h256
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp4
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp15
496 files changed, 16997 insertions, 7469 deletions
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 41726e41176..aa7d539538b 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -55,6 +55,10 @@
#include "BIF_gl.h"
#include "BLF_api.h"
+#ifndef BLF_STANDALONE
+#include "GPU_basic_shader.h"
+#endif
+
#include "blf_internal_types.h"
#include "blf_internal.h"
@@ -179,6 +183,16 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#ifndef BLF_STANDALONE
+ /* needed since basic shader doesn't support alpha-only textures,
+ * while we could add support this is only used in a few places
+ * (an alternative could be to have a simple shader for BLF). */
+ if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) {
+ GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
+ }
+#endif
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
}
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 8ccc4a6eb0e..606488f85cc 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -694,7 +694,7 @@ DerivedMesh *mesh_create_derived_render(
CustomDataMask dataMask);
DerivedMesh *getEditDerivedBMesh(
- struct BMEditMesh *em, struct Object *ob,
+ struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask,
float (*vertexCos)[3]);
DerivedMesh *mesh_create_derived_index_render(
@@ -723,7 +723,7 @@ DerivedMesh *mesh_create_derived_physics(
CustomDataMask dataMask);
DerivedMesh *editbmesh_get_derived_base(
- struct Object *, struct BMEditMesh *em);
+ struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask);
DerivedMesh *editbmesh_get_derived_cage(
struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 6524afff051..772e08589c1 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -62,7 +62,7 @@ struct AnimData *BKE_animdata_add_id(struct ID *id);
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
/* Free AnimData */
-void BKE_animdata_free(struct ID *id);
+void BKE_animdata_free(struct ID *id, const bool do_id_user);
/* Copy AnimData */
struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 8ce85c8e615..d2d9c763031 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void);
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
+/* Blenders' own atexit (avoids leaking) */
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data);
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data);
+void BKE_blender_atexit(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index cd18bd8db40..9547eeb9838 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
+extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 7bd3ca88076..07db2217bac 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -43,9 +43,11 @@ struct BMEditMesh;
struct MVert;
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;
@@ -54,11 +56,13 @@ typedef struct BVHTreeFromEditMesh {
BVHTree_RayCastCallback raycast_callback;
BVHTree_NearestToRayCallback nearest_to_ray_callback;
+ struct BMEditMesh *em;
+
/* radius for raycast */
float sphere_radius;
/* Private data */
- struct BMEditMesh *em;
+ bool cached;
} BVHTreeFromEditMesh;
@@ -118,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);
@@ -133,12 +145,12 @@ BVHTree *bvhtree_from_mesh_faces_ex(
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_editmesh_looptri(
- BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon,
- int tree_type, int axis);
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache);
BVHTree *bvhtree_from_editmesh_looptri_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *mask, int looptri_num_active,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache);
BVHTree *bvhtree_from_mesh_looptri(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
@@ -165,9 +177,7 @@ float bvhtree_ray_tri_intersection(
float bvhtree_sphereray_tri_intersection(
const BVHTreeRay *ray, float radius, const float m_dist,
const float v0[3], const float v1[3], const float v2[3]);
-float nearest_point_in_tri_surface_squared(
- const float v0[3], const float v1[3], const float v2[3],
- const float p[3], int *v, int *e, float nearest[3]);
+
/**
* BVHCache
@@ -179,9 +189,10 @@ enum {
BVHTREE_FROM_EDGES = 1,
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
+
+ BVHTREE_FROM_EM_LOOPTRI = 4,
};
-typedef struct LinkNode BVHCache;
BVHTree *bvhcache_find(BVHCache *cache, int type);
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
@@ -189,4 +200,5 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
void bvhcache_init(BVHCache **cache_p);
void bvhcache_free(BVHCache **cache_p);
+
#endif
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 061270b8b41..659884d96a4 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -66,7 +66,6 @@ typedef struct CurveCache {
#define CU_DO_2DFILL(cu) ((((cu)->flag & CU_3D) == 0) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0))
/* ** Curve ** */
-void BKE_curve_unlink(struct Curve *cu);
void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
@@ -151,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_displist.h b/source/blender/blenkernel/BKE_displist.h
index 3b096773d96..9625f05192a 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -45,10 +45,14 @@
#define DL_VERTS 7
/* dl->flag */
-#define DL_CYCL_U 1
-#define DL_CYCL_V 2
-#define DL_FRONT_CURVE 4
-#define DL_BACK_CURVE 8
+enum {
+ /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */
+ DL_CYCL_U = (1 << 0),
+ DL_CYCL_V = (1 << 1),
+
+ DL_FRONT_CURVE = (1 << 2),
+ DL_BACK_CURVE = (1 << 3),
+};
/* prototypes */
@@ -70,7 +74,7 @@ typedef struct DispList {
int charidx;
int totindex; /* indexed array drawing surfaces */
- unsigned int *bevelSplitFlag;
+ unsigned int *bevel_split; /* BLI_bitmap */
} DispList;
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 9056e48cf50..ae6e52b613b 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -41,7 +41,6 @@ struct Object;
struct Scene;
void BKE_group_free(struct Group *group);
-void BKE_group_unlink(struct Main *bmain, struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
struct Group *BKE_group_copy(struct Group *group);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 2215fbfbd7d..56f040ab260 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -60,13 +60,15 @@ void BKE_libblock_relink(struct ID *id);
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
+struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+/* library_remap.c (keep here since they're general functions) */
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
-
-struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
@@ -82,7 +84,6 @@ void id_fake_user_clear(struct ID *id);
bool id_make_local(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_unlink(struct ID *id, int test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
@@ -119,16 +120,11 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain);
/* (MAX_ID_NAME - 2) + 3 */
void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
+void BKE_library_free(struct Library *lib);
+
void BKE_library_make_local(
struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
-typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
-typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *);
-
-void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
-void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_idmap.h b/source/blender/blenkernel/BKE_library_idmap.h
new file mode 100644
index 00000000000..971586ea8b7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_idmap.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_LIBRARY_IDMAP_H__
+#define __BKE_LIBRARY_IDMAP_H__
+
+/** \file BKE_library_idmap.h
+ * \ingroup bke
+ */
+
+#include "BLI_compiler_attrs.h"
+
+struct ID;
+struct Main;
+struct IDNameLib_Map;
+
+struct IDNameLib_Map *BKE_main_idmap_create(
+ struct Main *bmain)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_main_idmap_destroy(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_NONNULL();
+struct Main *BKE_main_idmap_main_get(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_main_idmap_lookup(
+ struct IDNameLib_Map *id_typemap,
+ short id_type, const char *name, const struct Library *lib)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3);
+struct ID *BKE_main_idmap_lookup_id(
+ struct IDNameLib_Map *id_typemap, const struct ID *id)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+
+#endif /* __BKE_LIBRARY_IDMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 2e73be576f9..3a2b49f911c 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -32,6 +32,7 @@
*/
struct ID;
+struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
enum {
@@ -52,7 +53,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. */
};
@@ -75,4 +76,6 @@ 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_ID_is_indirectly_used(struct Main *bmain, void *idv);
+
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
new file mode 100644
index 00000000000..754005276f0
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -0,0 +1,78 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_LIBRARY_REMAP_H__
+#define __BKE_LIBRARY_REMAP_H__
+
+/** \file BKE_library_remap.h
+ * \ingroup bke
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_compiler_attrs.h"
+
+/* BKE_libblock_free, delete are declared in BKE_library.h for convenience. */
+
+/* Also IDRemap->flag. */
+enum {
+ /* Do not remap indirect usages of IDs (that is, when user is some linked data). */
+ ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0,
+ /* This flag should always be set, *except for 'unlink' scenarios* (only relevant when new_id == NULL).
+ * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed) old_id user count
+ * will still be decremented. This is mandatory for 'delete ID' case, but in all other situation this would lead
+ * to invalid user counts! */
+ ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1,
+ /* This tells the callback func to flag with LIB_DOIT all IDs using target one with a 'never NULL' pointer
+ * (like e.g. Object->data). */
+ ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2,
+ /* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL.
+ * WARNING! Use with extreme care, this will leave database in broken state! */
+ ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
+};
+
+/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
+void BKE_libblock_remap_locked(
+ struct Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags) ATTR_NONNULL(1, 2);
+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, 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);
+
+
+typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
+typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
+typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
+void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_LIBRARY_REMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index e3eead4102c..e343cd29622 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -79,8 +79,6 @@ void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineSty
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp);
-void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob);
-
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes);
void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle);
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 25893d54dca..f3d12b5a8cc 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -125,8 +125,7 @@ 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);
-void BKE_mask_free_nolib(struct Mask *mask);
-void BKE_mask_free(struct Main *bmain, struct Mask *mask);
+void BKE_mask_free(struct Mask *mask);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 0574b88bef3..b8258455c65 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -38,7 +38,6 @@ struct Object;
struct Scene;
struct MetaElem;
-void BKE_mball_unlink(struct MetaBall *mb);
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);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index c7d5857b873..2cc28ca837f 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,
@@ -81,8 +84,7 @@ int poly_get_adj_loops_from_vert(
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
-void BKE_mesh_unlink(struct Mesh *me);
-void BKE_mesh_free(struct Mesh *me, int unlink);
+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);
@@ -323,7 +325,7 @@ void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip_ex(
struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata,
- struct MDisps *mdisp, const bool use_loop_mdisp_flip);
+ float (*lnors)[3], struct MDisps *mdisp, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index afca326c727..3d963ac109c 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -40,7 +40,6 @@ struct MovieClipUser;
struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
-void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 76e49566d19..bf198c9b86b 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -334,7 +334,6 @@ void ntreeInitDefault(struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
-void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user);
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);
@@ -348,6 +347,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeMakeLocal(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);
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 7d6096407ff..f46fb73f4c9 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -65,7 +65,6 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob);
void BKE_object_free(struct Object *ob);
-void BKE_object_free_ex(struct Object *ob, bool do_id_user);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
@@ -79,7 +78,6 @@ void BKE_object_free_modifiers(struct Object *ob);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
-void BKE_object_unlink(struct Main *bmain, struct Object *ob);
bool BKE_object_exists_check(struct Object *obtest);
bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
@@ -208,6 +206,8 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
+void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob);
+
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index e17fb9f7a02..5daa94c4302 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -148,7 +148,8 @@ typedef struct ParticleThreadContext {
struct ParticleData *tpars;
/* path caching */
- int editupdate, between, segments, extra_segments;
+ bool editupdate;
+ int between, segments, extra_segments;
int totchild, totparent, parent_pass;
float cfra;
@@ -293,7 +294,7 @@ void psys_set_current_num(Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
-bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
+bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
void psys_check_group_weights(struct ParticleSettings *part);
@@ -327,11 +328,11 @@ void BKE_particlesettings_make_local(struct ParticleSettings *part);
void psys_reset(struct ParticleSystem *psys, int mode);
-void psys_find_parents(struct ParticleSimulationData *sim);
+void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
-void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
-void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
-void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
+void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params);
+void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
+void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params);
int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
@@ -379,7 +380,7 @@ void psys_check_boid_data(struct ParticleSystem *psys);
void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra);
-void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
+void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
/* Callback format for performing operations on ID-pointers for particle systems */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index fa448aa97b8..1743a4431fd 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -67,7 +67,6 @@ void clear_sca_new_poins_ob(struct Object *ob);
void clear_sca_new_poins(void);
void set_sca_new_poins_ob(struct Object *ob);
void set_sca_new_poins(void);
-void sca_remove_ob_poin(struct Object *obt, struct Object *ob);
void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up);
void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index a4c44b9934e..ccb7dc8e015 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -100,10 +100,11 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
struct Scene *BKE_scene_copy(struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
-void BKE_scene_unlink(struct Main *bmain, struct Scene *sce, struct Scene *newsce);
struct Object *BKE_scene_camera_find(struct Scene *sc);
+#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
+#endif
int BKE_scene_camera_switch_update(struct Scene *scene);
char *BKE_scene_find_marker_name(struct Scene *scene, int frame);
@@ -135,6 +136,7 @@ float get_render_aosss_error(const struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
+bool BKE_scene_use_world_space_shading(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
bool BKE_scene_uses_blender_internal(const struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index d05df3470b5..14e978b23f2 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -99,6 +99,9 @@ typedef struct SpaceType {
/* return context data */
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);
+ /* Used when we want to replace an ID by another (or NULL). */
+ void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
+
/* region type definitions */
ListBase regiontypes;
@@ -274,8 +277,8 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *));
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 67db2537c8f..18d9fe061a8 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -72,8 +72,6 @@ struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source);
struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
#endif
-void BKE_sound_delete(struct Main *bmain, struct bSound *sound);
-
void BKE_sound_cache(struct bSound *sound);
void BKE_sound_delete_cache(struct bSound *sound);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b14593f5a56..858feeeab10 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
-void BKE_text_unlink (struct Main *bmain, struct Text *text);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
int BKE_text_file_modified_check(struct Text *text);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index 8d7ab230919..0be61fe0229 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -37,7 +37,6 @@ struct Main;
struct World;
void BKE_world_free(struct World *sc);
-void BKE_world_free_ex(struct World *sc, bool do_id_user);
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);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index afab0ccc5a5..b7ff81d603b 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -49,9 +49,6 @@ set(INC
../../../intern/smoke/extern
../../../intern/atomic
../../../intern/libmv
-
- # XXX - BAD LEVEL CALL WM_api.h
- ../windowmanager
)
set(INC_SYS
@@ -121,7 +118,9 @@ set(SRC
intern/lamp.c
intern/lattice.c
intern/library.c
+ intern/library_idmap.c
intern/library_query.c
+ intern/library_remap.c
intern/linestyle.c
intern/mask.c
intern/mask_evaluate.c
@@ -244,7 +243,9 @@ set(SRC
BKE_lamp.h
BKE_lattice.h
BKE_library.h
+ BKE_library_idmap.h
BKE_library_query.h
+ BKE_library_remap.h
BKE_linestyle.h
BKE_main.h
BKE_mask.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 0de0e4d7797..79e500f8ceb 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -1433,10 +1433,12 @@ static void calc_weightpaint_vert_array(
Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo,
unsigned char (*r_wtcol_v)[4])
{
- MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
- int numVerts = dm->getNumVerts(dm);
+ BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
+ const int numVerts = dm->getNumVerts(dm);
- if (dv && (ob->actdef != 0)) {
+ if ((ob->actdef != 0) &&
+ (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT)))
+ {
unsigned char (*wc)[4] = r_wtcol_v;
unsigned int i;
@@ -1455,8 +1457,30 @@ static void calc_weightpaint_vert_array(
}
}
- for (i = numVerts; i != 0; i--, wc++, dv++) {
- calc_weightpaint_vert_color((unsigned char *)wc, dv, dm_wcinfo, defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ /* editmesh won't have deform verts unless modifiers require it,
+ * avoid having to create an array of deform-verts only for drawing
+ * by reading from the bmesh directly. */
+ if (em) {
+ BMIter iter;
+ BMVert *eve;
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ BLI_assert(cd_dvert_offset != -1);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ wc++;
+ }
+ }
+ else {
+ const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
+ for (i = numVerts; i != 0; i--, wc++, dv++) {
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ }
}
if (defbase_sel) {
@@ -2282,7 +2306,7 @@ static void editbmesh_calc_modifiers(
modifiers_clearErrors(ob);
if (r_cage && cageIndex == -1) {
- *r_cage = getEditDerivedBMesh(em, ob, NULL);
+ *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL);
}
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -2448,7 +2472,7 @@ static void editbmesh_calc_modifiers(
}
else {
*r_cage = getEditDerivedBMesh(
- em, ob,
+ em, ob, mask,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2484,7 +2508,7 @@ static void editbmesh_calc_modifiers(
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- *r_final = getEditDerivedBMesh(em, ob, deformedVerts);
+ *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts);
deformedVerts = NULL;
/* In this case, we should never have weight-modifying modifiers in stack... */
@@ -2847,9 +2871,9 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh
return em->derivedCage;
}
-DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
+DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask)
{
- return getEditDerivedBMesh(em, obedit, NULL);
+ return getEditDerivedBMesh(em, obedit, data_mask, NULL);
}
/***/
@@ -3881,7 +3905,6 @@ static void navmesh_drawColored(DerivedMesh *dm)
/* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
{
DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- //glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
for (a = 0; a < dm->numTessFaceData; a++, mface++) {
int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index df9b9683687..46ee8a4d888 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -159,22 +159,19 @@ void BKE_action_make_local(bAction *act)
/* .................................. */
+/** Free (or release) any data used by this action (does not free the action itself). */
void BKE_action_free(bAction *act)
-{
- /* sanity check */
- if (act == NULL)
- return;
-
+{
+ /* No animdata here. */
+
/* Free F-Curves */
free_fcurves(&act->curves);
/* Free groups */
- if (act->groups.first)
- BLI_freelistN(&act->groups);
+ BLI_freelistN(&act->groups);
/* Free pose-references (aka local markers) */
- if (act->markers.first)
- BLI_freelistN(&act->markers);
+ BLI_freelistN(&act->markers);
}
/* .................................. */
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index dff696863e9..7d3d12ac112 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -340,11 +340,11 @@ static void motionpaths_calc_update_scene(Scene *scene)
}
}
#else // original, 'always correct' version
- /* do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- */
+ /* do all updates
+ * - if this is too slow, resort to using a more efficient way
+ * that doesn't force complete update, but for now, this is the
+ * most accurate way!
+ */
BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */
#endif
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 99aae6239e8..91b33f3efd3 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Freeing -------------------------------------------- */
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_animdata_free(ID *id)
+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
@@ -227,12 +227,14 @@ void BKE_animdata_free(ID *id)
/* check if there's any AnimData to start with */
if (adt) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action)
- id_us_min(&adt->action->id);
- /* same goes for the temporarily displaced action */
- if (adt->tmpact)
- id_us_min(&adt->tmpact->id);
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action)
+ id_us_min(&adt->action->id);
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact)
+ id_us_min(&adt->tmpact->id);
+ }
/* free nla data */
free_nladata(&adt->nla_tracks);
@@ -292,7 +294,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to);
+ BKE_animdata_free(id_to, true);
adt = BKE_animdata_from_id(id_from);
if (adt) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 04b4733fd44..b59618f46b2 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -120,30 +120,25 @@ void BKE_armature_bonelist_free(ListBase *lb)
BLI_freelistN(lb);
}
+/** Free (or release) any data used by this armature (does not free the armature itself). */
void BKE_armature_free(bArmature *arm)
{
- if (arm) {
- BKE_armature_bonelist_free(&arm->bonebase);
+ BKE_animdata_free(&arm->id, false);
- /* free editmode data */
- if (arm->edbo) {
- BLI_freelistN(arm->edbo);
+ BKE_armature_bonelist_free(&arm->bonebase);
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
+ /* free editmode data */
+ if (arm->edbo) {
+ BLI_freelistN(arm->edbo);
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
- /* free animation data */
- if (arm->adt) {
- BKE_animdata_free(&arm->id);
- arm->adt = NULL;
- }
+ /* free sketch */
+ if (arm->sketch) {
+ freeSketch(arm->sketch);
+ arm->sketch = NULL;
}
}
@@ -640,6 +635,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+
const float hlength1 = bone->ease1 * circle_factor;
const float hlength2 = bone->ease2 * circle_factor;
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 15492fbd20d..0805335da66 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -226,3 +226,56 @@ int BKE_blender_test_break(void)
return (G.is_break == true);
}
+
+/** \name Blender's AtExit
+ *
+ * \note Don't use MEM_mallocN so functions can be registered at any time.
+ * \{ */
+
+struct AtExitData {
+ struct AtExitData *next;
+
+ void (*func)(void *user_data);
+ void *user_data;
+} *g_atexit = NULL;
+
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
+{
+ struct AtExitData *ae = malloc(sizeof(*ae));
+ ae->next = g_atexit;
+ ae->func = func;
+ ae->user_data = user_data;
+ g_atexit = ae;
+}
+
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
+{
+ struct AtExitData *ae = g_atexit;
+ struct AtExitData **ae_p = &g_atexit;
+
+ while (ae) {
+ if ((ae->func == func) && (ae->user_data == user_data)) {
+ *ae_p = ae->next;
+ free(ae);
+ return;
+ }
+ ae_p = &ae;
+ ae = ae->next;
+ }
+}
+
+void BKE_blender_atexit(void)
+{
+ struct AtExitData *ae = g_atexit, *ae_next;
+ while (ae) {
+ ae_next = ae->next;
+
+ ae->func(ae->user_data);
+
+ free(ae);
+ ae = ae_next;
+ }
+ g_atexit = NULL;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index ca0a1b91cea..d64bf7ecf43 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -66,9 +66,6 @@
#include "BLO_readfile.h"
#include "BLO_writefile.h"
-#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie
-
-
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -87,6 +84,15 @@ typedef struct UndoElem {
static ListBase undobase = {NULL, NULL};
static UndoElem *curundo = NULL;
+/**
+ * Avoid bad-level call to #WM_jobs_kill_all_except()
+ */
+static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL;
+
+void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C))
+{
+ undo_wm_job_kill_callback = callback;
+}
static int read_undosave(bContext *C, UndoElem *uel)
{
@@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
int success = 0, fileflags;
/* This is needed so undoing/redoing doesn't crash with threaded previews going */
- WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+ undo_wm_job_kill_callback(C);
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index da7863096e3..44cacffb71f 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -202,37 +202,18 @@ Brush *BKE_brush_copy(Brush *brush)
return brushn;
}
-/* not brush itself */
+/** Free (or release) any data used by this brush (does not free the brush itself). */
void BKE_brush_free(Brush *brush)
{
- id_us_min((ID *)brush->mtex.tex);
- id_us_min((ID *)brush->mask_mtex.tex);
- id_us_min((ID *)brush->paint_curve);
-
- if (brush->icon_imbuf)
+ if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
-
- BKE_previewimg_free(&(brush->preview));
+ }
curvemapping_free(brush->curve);
- if (brush->gradient)
- MEM_freeN(brush->gradient);
-}
+ MEM_SAFE_FREE(brush->gradient);
-/**
- * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
- * This is only used by RNA, which can remove brushes.
- */
-void BKE_brush_unlink(Main *bmain, Brush *brush)
-{
- Brush *brush_iter;
-
- for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
- if (brush_iter->toggle_brush == brush) {
- brush_iter->toggle_brush = NULL;
- }
- }
+ BKE_previewimg_free(&(brush->preview));
}
static void extern_local_brush(Brush *brush)
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 7821946eb6e..264d87b86f3 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts(
/**
* Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
- * \param mask if not null, true elements give which vert to add to BVH tree.
+ * \param verts_mask if not null, true elements give which vert to add to BVH tree.
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
@@ -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,
@@ -804,7 +875,7 @@ BVHTree *bvhtree_from_mesh_faces(
* Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
* \param face_allocated if true, face freeing will be done when freeing data.
- * \param mask if not null, true elements give which faces to add to BVH tree.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
* \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
@@ -968,17 +1039,37 @@ static void bvhtree_from_mesh_looptri_setup_data(
BVHTree *bvhtree_from_editmesh_looptri_ex(
BVHTreeFromEditMesh *data, BMEditMesh *em,
const BLI_bitmap *looptri_mask, int looptri_num_active,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache)
{
/* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
+ * we _could_ tessellate here but rather not - campbell */
- BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis,
- em, em->tottri, looptri_mask, looptri_num_active);
+ BVHTree *tree;
+ if (bvhCache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ if (tree == NULL) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ if (tree == NULL) {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+ if (tree) {
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+ }
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+ }
if (tree) {
data->tree = tree;
@@ -987,17 +1078,18 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
data->nearest_to_ray_callback = NULL;
data->sphere_radius = 0.0f;
data->em = em;
+ data->cached = bvhCache != NULL;
}
return tree;
}
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache)
{
return bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1,
- epsilon, tree_type, axis);
+ epsilon, tree_type, axis, bvhCache);
}
/**
@@ -1045,6 +1137,9 @@ BVHTree *bvhtree_from_mesh_looptri(
tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
if (tree == NULL) {
int looptri_num = dm->getNumLoopTri(dm);
+
+ /* this assert checks we have looptris,
+ * if not caller should use DM_ensure_looptri() */
BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_looptri_create_tree(
@@ -1102,7 +1197,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
if (data->tree) {
- BLI_bvhtree_free(data->tree);
+ if (!data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
memset(data, 0, sizeof(*data));
}
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 96bac2c2f41..eabee742327 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -153,9 +153,10 @@ void BKE_camera_make_local(Camera *cam)
}
}
+/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
- BKE_animdata_free((ID *)ca);
+ BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index e7e6118813e..159d5b82a6c 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -61,8 +61,6 @@
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
-#include "WM_api.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -464,7 +462,6 @@ static void cdDM_drawFacesSolid(
BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
setMaterial, false, false);
- glShadeModel(GL_FLAT);
return;
}
}
@@ -472,7 +469,6 @@ static void cdDM_drawFacesSolid(
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
- glShadeModel(GL_SMOOTH);
for (a = 0; a < dm->drawObject->totmaterial; a++) {
if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
GPU_buffer_draw_elements(
@@ -481,8 +477,6 @@ static void cdDM_drawFacesSolid(
}
}
GPU_buffers_unbind();
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawFacesTex_common(
@@ -553,8 +547,7 @@ static void cdDM_drawFacesTex_common(
if (mloopcol) {
GPU_color_setup(dm, colType);
}
-
- glShadeModel(GL_SMOOTH);
+
/* lastFlag = 0; */ /* UNUSED */
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
@@ -633,7 +626,6 @@ static void cdDM_drawFacesTex_common(
}
GPU_buffers_unbind();
- glShadeModel(GL_FLAT);
}
@@ -705,10 +697,10 @@ static void cdDM_drawMappedFaces(
}
if ((orig != ORIGINDEX_NONE) && !is_hidden)
- WM_framebuffer_index_get(orig + 1, &selcol);
+ GPU_select_index_get(orig + 1, &selcol);
}
else if (orig != ORIGINDEX_NONE)
- WM_framebuffer_index_get(orig + 1, &selcol);
+ GPU_select_index_get(orig + 1, &selcol);
for (j = 0; j < mpoly->totloop; j++)
fi_map[start_element++] = selcol;
@@ -742,9 +734,6 @@ static void cdDM_drawMappedFaces(
}
}
}
-
-
- glShadeModel(GL_SMOOTH);
tot_tri_elem = dm->drawObject->tot_triangle_point;
@@ -841,7 +830,6 @@ static void cdDM_drawMappedFaces(
}
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glShadeModel(GL_FLAT);
GPU_buffers_unbind();
@@ -929,8 +917,6 @@ static void cdDM_drawMappedFacesGLSL(
matnr = -1;
do_draw = false;
- glShadeModel(GL_SMOOTH);
-
if (setDrawOptions != NULL) {
DMVertexAttribs attribs;
DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
@@ -1153,8 +1139,6 @@ static void cdDM_drawMappedFacesGLSL(
MEM_freeN(mat_orig_to_new);
MEM_freeN(matconv);
}
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
@@ -1203,8 +1187,6 @@ static void cdDM_drawMappedFacesMat(
matnr = -1;
- glShadeModel(GL_SMOOTH);
-
memset(&attribs, 0, sizeof(attribs));
glBegin(GL_TRIANGLES);
@@ -1260,8 +1242,6 @@ static void cdDM_drawMappedFacesMat(
cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
}
glEnd();
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData)
@@ -2660,6 +2640,9 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const
}
/* #define DEBUG_CLNORS */
+#ifdef DEBUG_CLNORS
+# include "BLI_linklist.h"
+#endif
void CDDM_calc_loop_normals_spacearr(
DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index c8de0786697..56df8e51eba 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -39,6 +39,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BKE_crazyspace.h"
@@ -275,7 +276,13 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
if (!defmats) {
- dm = getEditDerivedBMesh(em, ob, NULL);
+ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+ CustomDataMask data_mask = CD_MASK_BAREMESH;
+ CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, data_mask, required_mode, NULL, 0);
+ data_mask = datamasks->mask;
+ BLI_linklist_free((LinkNode *)datamasks, NULL);
+
+ dm = getEditDerivedBMesh(em, ob, data_mask, NULL);
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 8afb451f768..c52b0f6a884 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -69,36 +69,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c
short cox, short coy,
float *lambda, float *mu, float vec[3]);
-void BKE_curve_unlink(Curve *cu)
-{
- int a;
-
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a])
- id_us_min(&cu->mat[a]->id);
- cu->mat[a] = NULL;
- }
- if (cu->vfont)
- id_us_min(&cu->vfont->id);
- cu->vfont = NULL;
-
- if (cu->vfontb)
- id_us_min(&cu->vfontb->id);
- cu->vfontb = NULL;
-
- if (cu->vfonti)
- id_us_min(&cu->vfonti->id);
- cu->vfonti = NULL;
-
- if (cu->vfontbi)
- id_us_min(&cu->vfontbi->id);
- cu->vfontbi = NULL;
-
- if (cu->key)
- id_us_min(&cu->key->id);
- cu->key = NULL;
-}
-
/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
@@ -136,26 +106,21 @@ void BKE_curve_editNurb_free(Curve *cu)
}
}
-/* don't free curve itself */
+/** Free (or release) any data used by this curve (does not free the curve itself). */
void BKE_curve_free(Curve *cu)
{
+ BKE_animdata_free((ID *)cu, false);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
BKE_curve_editNurb_free(cu);
- BKE_curve_unlink(cu);
- BKE_animdata_free((ID *)cu);
-
- if (cu->mat)
- MEM_freeN(cu->mat);
- if (cu->str)
- MEM_freeN(cu->str);
- if (cu->strinfo)
- MEM_freeN(cu->strinfo);
- if (cu->bb)
- MEM_freeN(cu->bb);
- if (cu->tb)
- MEM_freeN(cu->tb);
+
+ MEM_SAFE_FREE(cu->mat);
+ MEM_SAFE_FREE(cu->str);
+ MEM_SAFE_FREE(cu->strinfo);
+ MEM_SAFE_FREE(cu->bb);
+ MEM_SAFE_FREE(cu->tb);
}
void BKE_curve_init(Curve *cu)
@@ -1419,6 +1384,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;
+}
+
+/**
+ * Calcualte 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/customdata.c b/source/blender/blenkernel/intern/customdata.c
index de79a30bd60..612f1f477e1 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1853,8 +1853,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
(alloctype == CD_DUPLICATE) ||
(alloctype == CD_REFERENCE));
- BLI_assert(size >= 0);
-
if (!typeInfo->defaultname && CustomData_has_layer(data, type))
return &data->layers[CustomData_get_layer_index(data, type)];
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 14c230e4a45..8ea65bf92c1 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -770,7 +770,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
@@ -2285,7 +2285,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
ParticleSystem *psys = ob->particlesystem.first;
for (; psys; psys = psys->next) {
- if (psys_check_enabled(ob, psys)) {
+ if (psys_check_enabled(ob, psys, G.is_rendering)) {
ob->recalc |= OB_RECALC_DATA;
break;
}
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 98cbe47c7f9..49db75a0474 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl)
if (dl->verts) MEM_freeN(dl->verts);
if (dl->nors) MEM_freeN(dl->nors);
if (dl->index) MEM_freeN(dl->index);
- if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
+ if (dl->bevel_split) MEM_freeN(dl->bevel_split);
MEM_freeN(dl);
}
}
@@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb)
dln->nors = MEM_dupallocN(dl->nors);
dln->index = MEM_dupallocN(dl->index);
- if (dl->bevelSplitFlag)
- dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag);
+ if (dl->bevel_split) {
+ dln->bevel_split = MEM_dupallocN(dl->bevel_split);
+ }
dl = dl->next;
}
@@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (dlb->type == DL_POLY) {
dl->flag |= DL_CYCL_U;
}
- if ((bl->poly >= 0) && (steps != 2)) {
+ if ((bl->poly >= 0) && (steps > 2)) {
dl->flag |= DL_CYCL_V;
}
@@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
/* CU_2D conflicts with R_NOPUNOFLIP */
dl->rt = nu->flag & ~CU_2D;
- dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5),
- "bevelSplitFlag");
+ dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
/* for each point of poly make a bevel piece */
bevp_first = bl->bevpoints;
@@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (bevp->split_tag) {
- dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F);
+ BLI_BITMAP_ENABLE(dl->bevel_split, a);
}
/* rotate bevel piece and write in data */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 2d531e32f69..6207217f2c7 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -1826,14 +1826,14 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
BLI_task_parallel_range(0, sData->total_points, &data,
dynamic_paint_apply_surface_vpaint_blend_cb,
- sData->total_points > 1000);
+ sData->total_points > 1000);
/* paint layer */
MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
mloopcol = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
/* wet layer */
@@ -1841,7 +1841,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
mloopcol_wet = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
}
/* Save preview results to weight layer to be able to share same drawing methods */
@@ -1850,7 +1850,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
if (!mloopcol_preview) {
mloopcol_preview = CustomData_add_layer(
- &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
@@ -2367,15 +2367,15 @@ static int dynamic_paint_find_neighbour_pixel(
edge1_index = 0;
edge2_index = 1;
dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
/* Dist to second edge */
t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
if (t_dist_squared < dist_squared) {
e1_index = cPoint->v2;
e2_index = cPoint->v3;
@@ -2386,9 +2386,9 @@ static int dynamic_paint_find_neighbour_pixel(
/* Dist to third edge */
t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
if (t_dist_squared < dist_squared) {
e1_index = cPoint->v3;
e2_index = cPoint->v1;
@@ -2439,9 +2439,9 @@ static int dynamic_paint_find_neighbour_pixel(
//printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
+ (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
+ ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
{
return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
}
@@ -2451,15 +2451,15 @@ static int dynamic_paint_find_neighbour_pixel(
* on this other face UV
*/
lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
+ closest_point, pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
CLAMP(lambda, 0.0f, 1.0f);
sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ dir_vec,
+ mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
+ mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
mul_v2_fl(dir_vec, lambda);
@@ -2678,8 +2678,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
if (f_data) {
f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
- f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights),
- "PaintUVPoint");
+ f_data->barycentricWeights =
+ MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
if (!f_data->uv_p || !f_data->barycentricWeights)
error = 1;
@@ -2881,7 +2881,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf};
- switch(surface->type) {
+ switch (surface->type) {
case MOD_DPAINT_SURFACE_T_PAINT:
switch (output_layer) {
case 0:
@@ -3883,12 +3883,12 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* loop through cell points and process brush */
DynamicPaintPaintData data = {
- .surface = surface,
+ .surface = surface,
.brush = brush, .brushOb = brushOb, .bMats = bMats,
.scene = scene, .timescale = timescale, .c_index = c_index,
- .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
- .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
- .treeData = &treeData
+ .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
+ .treeData = &treeData
};
BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
dynamic_paint_paint_mesh_cell_point_cb_ex,
@@ -4170,10 +4170,10 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
/* loop through cell points */
DynamicPaintPaintData data = {
- .surface = surface,
+ .surface = surface,
.brush = brush, .psys = psys,
.solidradius = solidradius, .timescale = timescale, .c_index = c_index,
- .treeData = tree,
+ .treeData = tree,
};
BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
dynamic_paint_paint_particle_cell_point_cb_ex,
@@ -4313,16 +4313,16 @@ static int dynamicPaint_paintSinglePoint(
* Loop through every surface point
*/
DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
- .scene = scene, .timescale = timescale,
- .mvert = mvert,
- .brush_radius = brush_radius, .brushVelocity = &brushVel,
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius, .brushVelocity = &brushVel,
.pointCoord = pointCoord,
};
BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
- dynamic_paint_paint_single_point_cb_ex,
- sData->total_points > 1000, true);
+ dynamic_paint_paint_single_point_cb_ex,
+ sData->total_points > 1000, true);
return 1;
}
@@ -4755,83 +4755,83 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
{
const DynamicPaintEffectData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const PaintPoint *pPoint_prev = &prevPoint[index];
- const float *force = data->force;
- const float eff_scale = data->eff_scale;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
- const int *n_target = sData->adj_data->n_target;
+ const int *n_target = sData->adj_data->n_target;
- uint8_t *point_locks = data->point_locks;
+ uint8_t *point_locks = data->point_locks;
- int closest_id[2];
- float closest_d[2];
+ int closest_id[2];
+ float closest_d[2];
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0)
- return;
- CLAMP(w_factor, 0.0f, 1.0f);
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
- /* Apply movement towards those two points */
- for (int i = 0; i < 2; i++) {
- const int n_idx = closest_id[i];
- if (n_idx != -1 && closest_d[i] > 0.0f) {
- const float dir_dot = closest_d[i];
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
- float dir_factor, a_factor;
- const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
- const unsigned int n_trgt = (unsigned int)n_target[n_idx];
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
- /* Sort of spinlock, but only for given ePoint.
- * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
- * much more eficient than a global spin lock. */
- const unsigned int pointlock_idx = n_trgt / 8;
- const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more eficient than a global spin lock. */
+ const unsigned int pointlock_idx = n_trgt / 8;
+ const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
- const float e_wet = ePoint->wetness;
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
- dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
- /* mix new color */
- a_factor = dir_factor / pPoint_prev->wetness;
- CLAMP(a_factor, 0.0f, 1.0f);
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
- /* dripping is supposed to preserve alpha level */
- if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
- ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
+ /* mix new color */
+ a_factor = dir_factor / pPoint_prev->wetness;
+ CLAMP(a_factor, 0.0f, 1.0f);
+ mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
+ /* dripping is supposed to preserve alpha level */
+ if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
+ ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+ /* decrease paint wetness on current point */
+ pPoint->wetness -= (ePoint->wetness - e_wet);
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
#ifndef NDEBUG
uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
- BLI_assert(ret & pointlock_bitmask);
+ BLI_assert(ret & pointlock_bitmask);
#else
atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
#endif
- }
+ }
}
}
@@ -4892,7 +4892,7 @@ static void dynamicPaint_doEffectStep(
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint,
+ .surface = surface, .prevPoint = prevPoint,
.eff_scale = eff_scale, .force = force,
.point_locks = point_locks,
};
@@ -5108,7 +5108,7 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
if (pPoint->color[3]) {
for (i = 0; i < 3; i++) {
pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
- (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
}
}
}
@@ -5129,17 +5129,17 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
if (surface->flags & MOD_DPAINT_DISSOLVE) {
value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
CLAMP_MIN(pPoint->color[3], 0.0f);
value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
CLAMP_MIN(pPoint->e_color[3], 0.0f);
}
}
/* dissolve for float types */
else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
{
float *point = &((float *)sData->type_data)[index];
/* log or linear */
@@ -5388,7 +5388,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
*/
DynamicPaintGenerateBakeData data = {
.surface = surface, .ob = ob,
- .mvert = mvert, .canvas_verts = canvas_verts,
+ .mvert = mvert, .canvas_verts = canvas_verts,
.do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
};
BLI_task_parallel_range(
@@ -5503,7 +5503,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (brush->collision == MOD_DPAINT_COL_PSYS) {
if (brush->psys && brush->psys->part &&
ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys))
+ psys_check_enabled(brushObj, brush->psys, G.is_rendering))
{
/* Paint a particle system */
BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index ffd000eed88..1aba76baa2c 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -1181,6 +1181,14 @@ static void emDM_drawMappedFaces(
/* if non zero we know a face was rendered */
if (poly_prev != GL_ZERO) glEnd();
+
+ if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
+
+ if (shade_prev == GL_FLAT) {
+ glShadeModel(GL_SMOOTH);
+ }
}
static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset)
@@ -1236,8 +1244,6 @@ static void emDM_drawFacesTex_common(
// dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */
/* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
-
BM_mesh_elem_index_ensure(bm, BM_FACE);
/* call again below is ok */
@@ -1384,8 +1390,6 @@ static void emDM_drawFacesTex_common(
}
}
}
-
- glShadeModel(GL_FLAT);
}
static void emDM_drawFacesTex(
@@ -1524,8 +1528,6 @@ static void emDM_drawMappedFacesGLSL(
vertexNos = bmdm->vertexNos;
polyNos = bmdm->polyNos;
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
for (i = 0; i < em->tottri; i++) {
@@ -1636,8 +1638,6 @@ static void emDM_drawMappedFacesMat(
vertexNos = bmdm->vertexNos;
polyNos = bmdm->polyNos;
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
for (i = 0; i < em->tottri; i++) {
@@ -2226,16 +2226,17 @@ static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
return &bmdm->em->bm->pdata;
}
-
+/**
+ * \note This may be called per-draw,
+ * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh.
+ */
DerivedMesh *getEditDerivedBMesh(
- BMEditMesh *em,
- Object *UNUSED(ob),
+ BMEditMesh *em, struct Object *UNUSED(ob),
+ CustomDataMask data_mask,
float (*vertexCos)[3])
{
EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
BMesh *bm = em->bm;
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- const int cd_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
bmdm->em = em;
@@ -2304,6 +2305,9 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->vertexCos = (const float (*)[3])vertexCos;
bmdm->dm.deformedOnly = (vertexCos != NULL);
+ const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ?
+ CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1;
+
if (cd_dvert_offset != -1) {
BMIter iter;
BMVert *eve;
@@ -2317,6 +2321,9 @@ DerivedMesh *getEditDerivedBMesh(
}
}
+ const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ?
+ CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1;
+
if (cd_skin_offset != -1) {
BMIter iter;
BMVert *eve;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f06dd6f9de4..5090e46f1fc 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -139,9 +139,6 @@ void free_partdeflect(PartDeflect *pd)
if (!pd)
return;
- if (pd->tex)
- id_us_min(&pd->tex->id);
-
if (pd->rng)
BLI_rng_free(pd->rng);
@@ -182,7 +179,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec
{
ParticleSettings *part= psys->part;
- if ( !psys_check_enabled(ob, psys) )
+ if ( !psys_check_enabled(ob, psys, G.is_rendering) )
return;
if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index aed33d2c64d..5e1f8814ed6 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont)
}
}
+/** Free (or release) any data used by this font (does not free the font itself). */
void BKE_vfont_free(struct VFont *vf)
{
- if (vf == NULL) return;
-
BKE_vfont_free_data(vf);
if (vf->packedfile) {
@@ -541,7 +540,7 @@ int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
BLI_assert(ef->len >= 0);
BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
- BLI_assert(ef->selend >= 0 && ef->selend <= ef->len);
+ BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
if (ef->selstart == 0) {
@@ -628,6 +627,8 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
+ /* Text at the beginning of the last used text-box (use for y-axis alignment). */
+ int i_textbox = 0;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
float twidth, maxlen = 0;
@@ -830,6 +831,7 @@ makebreak:
(cu->totbox > (curbox + 1)) &&
((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
{
+ i_textbox = i + 1;
maxlen = 0;
curbox++;
@@ -908,10 +910,10 @@ makebreak:
/* linedata is now: width of line */
- if (cu->spacemode != CU_LEFT) {
+ if (cu->spacemode != CU_ALIGN_X_LEFT) {
ct = chartransdata;
- if (cu->spacemode == CU_RIGHT) {
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -923,7 +925,7 @@ makebreak:
ct++;
}
}
- else if (cu->spacemode == CU_MIDDLE) {
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -935,7 +937,7 @@ makebreak:
ct++;
}
}
- else if ((cu->spacemode == CU_FLUSH) && use_textbox) {
+ else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -956,7 +958,7 @@ makebreak:
ct++;
}
}
- else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) {
+ else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
float curofs = 0.0f;
for (i = 0; i <= slen; i++) {
for (j = i;
@@ -983,6 +985,60 @@ makebreak:
}
}
+ /* top-baseline is default, in this case, do nothing */
+ if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
+ if (tb_scale.h != 0.0f) {
+ /* top and top-baseline are the same when text-boxes are used */
+ if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
+ /* all previous textboxes are 'full', only align the last used text-box */
+ float yoff;
+ int lines;
+ struct CharTrans *ct_last, *ct_textbox;
+
+ ct_last = chartransdata + slen - 1;
+ ct_textbox = chartransdata + i_textbox;
+
+ lines = ct_last->linenr - ct_textbox->linenr + 1;
+ if (mem[slen - 1] == '\n') {
+ lines++;
+ }
+
+ if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
+ yoff = (lines * linedist) - tb_scale.h;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_CENTER) {
+ yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+ }
+
+ ct = ct_textbox;
+ for (i = i_textbox - 1; i < slen; i++) {
+ ct->yof += yoff;
+ ct++;
+ }
+ }
+ }
+ else {
+ /* non text-box case handled separately */
+ ct = chartransdata;
+ float yoff;
+
+ if (cu->align_y == CU_ALIGN_Y_TOP) {
+ yoff = -linedist;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
+ yoff = (lnr - 1.0f) * linedist;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_CENTER) {
+ yoff = (lnr - 2.0f) * linedist * 0.5f;
+ }
+
+ for (i = 0; i <= slen; i++) {
+ ct->yof += yoff;
+ ct++;
+ }
+ }
+ }
+
MEM_freeN(lineinfo);
/* TEXT ON CURVE */
@@ -1021,13 +1077,13 @@ makebreak:
/* path longer than text: spacemode involves */
distfac = 1.0f / distfac;
- if (cu->spacemode == CU_RIGHT) {
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
timeofs = 1.0f - distfac;
}
- else if (cu->spacemode == CU_MIDDLE) {
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
timeofs = (1.0f - distfac) / 2.0f;
}
- else if (cu->spacemode == CU_FLUSH) {
+ else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
distfac = 1.0f;
}
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index f3eb5430bce..af1bcd0c545 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -113,16 +113,13 @@ void free_gpencil_layers(ListBase *list)
}
/* Free all of GPencil datablock's related data, but not the block itself */
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free(bGPdata *gpd)
{
+ BKE_animdata_free(&gpd->id, false);
+
/* free layers */
free_gpencil_layers(&gpd->layers);
-
- /* free animation data */
- if (gpd->adt) {
- BKE_animdata_free(&gpd->id);
- gpd->adt = NULL;
- }
}
/* -------- Container Creation ---------- */
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index a44eb1df9fe..4fdee7e3633 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go)
MEM_freeN(go);
}
-
+/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
{
/* don't free group itself */
GroupObject *go;
- BKE_previewimg_free(&group->preview);
+ /* No animdata here. */
while ((go = BLI_pophead(&group->gobject))) {
free_group_object(go);
}
-}
-void BKE_group_unlink(Main *bmain, Group *group)
-{
- Material *ma;
- Object *ob;
- Scene *sce;
- SceneRenderLayer *srl;
- ParticleSystem *psys;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- Base *base = sce->base.first;
-
- /* ensure objects are not in this group */
- for (; base; base = base->next) {
- if (BKE_group_object_unlink(group, base->object, sce, base) &&
- BKE_group_object_find(NULL, base->object) == NULL)
- {
- base->object->flag &= ~OB_FROMGROUP;
- base->flag &= ~OB_FROMGROUP;
- }
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- FreestyleLineSet *lineset;
-
- if (srl->light_override == group)
- srl->light_override = NULL;
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
- if (lineset->group == group)
- lineset->group = NULL;
- }
- }
- }
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
-
- if (ob->dup_group == group) {
- ob->dup_group = NULL;
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part->dup_group == group)
- psys->part->dup_group = NULL;
-#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */
- if (psys->part->eff_group == group)
- psys->part->eff_group = NULL;
-#endif
- }
- }
-
- /* group stays in library, but no members */
- BKE_group_free(group);
- group->id.us = 0;
+ BKE_previewimg_free(&group->preview);
}
Group *BKE_group_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 68a741bc3fc..90b3713e47c 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "BKE_library.h"
#include "BKE_idcode.h"
typedef struct {
@@ -54,6 +55,7 @@ typedef struct {
/* plural need to match rna_main.c's MainCollectionDef */
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
+ /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
{ ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
@@ -61,7 +63,6 @@ static IDType idtypes[] = {
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
{ ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
{ ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
@@ -89,8 +90,14 @@ static IDType idtypes[] = {
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+
+ /** Keep last, not an ID exactly, only include for completeness */
+ { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
+/* -1 for ID_ID */
+BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType");
+
static IDType *idtype_from_name(const char *str)
{
int i = ARRAY_SIZE(idtypes);
@@ -117,7 +124,7 @@ static IDType *idtype_from_code(short idcode)
/**
* Return if the ID code is a valid ID code.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when invalid.
*/
bool BKE_idcode_is_valid(short idcode)
@@ -128,7 +135,7 @@ bool BKE_idcode_is_valid(short idcode)
/**
* Return non-zero when an ID type is linkable.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when non linkable.
*/
bool BKE_idcode_is_linkable(short idcode)
@@ -141,7 +148,7 @@ bool BKE_idcode_is_linkable(short idcode)
/**
* Convert an idcode into a name.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -254,7 +261,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
/**
* Convert an idcode into a name (plural).
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -268,7 +275,7 @@ const char *BKE_idcode_to_name_plural(short idcode)
/**
* Convert an idcode into its translations' context.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the i18n context of the code.
*/
const char *BKE_idcode_to_translation_context(short idcode)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 0b2c844cb2c..69384a70969 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -95,8 +95,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "WM_api.h"
-
static SpinLock image_spin;
/* prototypes */
@@ -324,20 +322,16 @@ void BKE_image_free_buffers(Image *ima)
ima->ok = IMA_OK;
}
-/* called by library too, do not free ima itself */
+/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
int a;
+ /* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- BKE_icon_id_delete(&ima->id);
- ima->id.icon_id = 0;
-
- BKE_previewimg_free(&ima->preview);
-
for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
if (ima->renders[a]) {
RE_FreeRenderResult(ima->renders[a]);
@@ -346,7 +340,10 @@ void BKE_image_free(Image *ima)
}
BKE_image_free_views(ima);
- MEM_freeN(ima->stereo3d_format);
+ MEM_SAFE_FREE(ima->stereo3d_format);
+
+ BKE_icon_id_delete(&ima->id);
+ BKE_previewimg_free(&ima->preview);
}
/* only image block itself */
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 362f41335d2..2517e2cc197 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -74,11 +74,13 @@
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+
+/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
{
KeyBlock *kb;
-
- BKE_animdata_free((ID *)key);
+
+ BKE_animdata_free((ID *)key, false);
while ((kb = BLI_pophead(&key->block))) {
if (kb->data)
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 49a573489ef..692b703f721 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -234,7 +234,7 @@ void BKE_lamp_free(Lamp *la)
MEM_freeN(mtex);
}
- BKE_animdata_free((ID *)la);
+ BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b350e932281..58c0a567116 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -300,24 +300,27 @@ Lattice *BKE_lattice_copy(Lattice *lt)
return ltn;
}
+/** Free (or release) any data used by this lattice (does not free the lattice itself). */
void BKE_lattice_free(Lattice *lt)
{
- if (lt->def) MEM_freeN(lt->def);
- if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ BKE_animdata_free(&lt->id, false);
+
+ MEM_SAFE_FREE(lt->def);
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
if (lt->editlatt) {
Lattice *editlt = lt->editlatt->latt;
- if (editlt->def) MEM_freeN(editlt->def);
- if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ if (editlt->def)
+ MEM_freeN(editlt->def);
+ if (editlt->dvert)
+ BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
MEM_freeN(editlt);
MEM_freeN(lt->editlatt);
- }
-
- /* free animation data */
- if (lt->adt) {
- BKE_animdata_free(&lt->id);
- lt->adt = NULL;
+ lt->editlatt = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 961b45df4e6..fe16df18813 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -84,7 +84,6 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -92,7 +91,6 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
-#include "BKE_ipo.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
@@ -103,16 +101,12 @@
#include "BKE_material.h"
#include "BKE_main.h"
#include "BKE_mball.h"
-#include "BKE_movieclip.h"
#include "BKE_mask.h"
#include "BKE_node.h"
#include "BKE_object.h"
-#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
#include "BKE_speaker.h"
-#include "BKE_sound.h"
-#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
@@ -125,10 +119,6 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#ifdef WITH_PYTHON
-#include "BPY_extern.h"
-#endif
-
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -182,7 +172,6 @@ void id_us_ensure_real(ID *id)
}
}
-/* Unused currently... */
void id_us_clear_real(ID *id)
{
if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
@@ -232,9 +221,7 @@ void id_us_min(ID *id)
if (id->us <= limit) {
printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
- /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero),
- * this is weak but it's how it works for now. */
- /* BLI_assert(0); */
+ BLI_assert(0);
id->us = limit;
}
else {
@@ -462,37 +449,6 @@ bool id_copy(ID *id, ID **newid, bool test)
return false;
}
-bool id_unlink(ID *id, int test)
-{
- Main *mainlib = G.main;
- short type = GS(id->name);
-
- switch (type) {
- case ID_TXT:
- if (test) return true;
- BKE_text_unlink(mainlib, (Text *)id);
- break;
- case ID_GR:
- if (test) return true;
- BKE_group_unlink(mainlib, (Group *)id);
- break;
- case ID_OB:
- if (test) return true;
- BKE_object_unlink(mainlib, (Object *)id);
- break;
- }
-
- if (id->us == 0) {
- if (test) return true;
-
- BKE_libblock_free(mainlib, id);
-
- return true;
- }
-
- return false;
-}
-
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -1111,234 +1067,12 @@ void BKE_libblock_relink(ID *id)
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
}
-static void BKE_library_free(Library *lib)
+void BKE_library_free(Library *lib)
{
if (lib->packedfile)
freePackedFile(lib->packedfile);
}
-static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
-
-void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
-{
- free_windowmanager_cb = func;
-}
-
-static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
-
-void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
-{
- free_notifier_reference_cb = func;
-}
-
-static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
-
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func)
-{
- free_editor_id_reference_cb = func;
-}
-
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
-void BKE_libblock_free_data(Main *bmain, ID *id)
-{
- if (id->properties) {
- IDP_FreeProperty(id->properties);
- MEM_freeN(id->properties);
- }
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
-}
-
-/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
-void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
-{
- ID *id = idv;
- short type = GS(id->name);
- ListBase *lb = which_libbase(bmain, type);
-
- DAG_id_type_tag(bmain, type);
-
-#ifdef WITH_PYTHON
- BPY_id_release(id);
-#endif
-
- switch (type) { /* GetShort from util.h */
- case ID_SCE:
- BKE_scene_free((Scene *)id);
- break;
- case ID_LI:
- BKE_library_free((Library *)id);
- break;
- case ID_OB:
- BKE_object_free_ex((Object *)id, do_id_user);
- break;
- case ID_ME:
- BKE_mesh_free((Mesh *)id, 1);
- break;
- case ID_CU:
- BKE_curve_free((Curve *)id);
- break;
- case ID_MB:
- BKE_mball_free((MetaBall *)id);
- break;
- case ID_MA:
- BKE_material_free((Material *)id);
- break;
- case ID_TE:
- BKE_texture_free((Tex *)id);
- break;
- case ID_IM:
- BKE_image_free((Image *)id);
- break;
- case ID_LT:
- BKE_lattice_free((Lattice *)id);
- break;
- case ID_LA:
- BKE_lamp_free((Lamp *)id);
- break;
- case ID_CA:
- BKE_camera_free((Camera *) id);
- break;
- case ID_IP:
- BKE_ipo_free((Ipo *)id);
- break;
- case ID_KE:
- BKE_key_free((Key *)id);
- break;
- case ID_WO:
- BKE_world_free((World *)id);
- break;
- case ID_SCR:
- BKE_screen_free((bScreen *)id);
- break;
- case ID_VF:
- BKE_vfont_free((VFont *)id);
- break;
- case ID_TXT:
- BKE_text_free((Text *)id);
- break;
- case ID_SPK:
- BKE_speaker_free((Speaker *)id);
- break;
- case ID_SO:
- BKE_sound_free((bSound *)id);
- break;
- case ID_GR:
- BKE_group_free((Group *)id);
- break;
- case ID_AR:
- BKE_armature_free((bArmature *)id);
- break;
- case ID_AC:
- BKE_action_free((bAction *)id);
- break;
- case ID_NT:
- ntreeFreeTree_ex((bNodeTree *)id, do_id_user);
- break;
- case ID_BR:
- BKE_brush_free((Brush *)id);
- break;
- case ID_PA:
- BKE_particlesettings_free((ParticleSettings *)id);
- break;
- case ID_WM:
- if (free_windowmanager_cb)
- free_windowmanager_cb(NULL, (wmWindowManager *)id);
- break;
- case ID_GD:
- BKE_gpencil_free((bGPdata *)id);
- break;
- case ID_MC:
- BKE_movieclip_free((MovieClip *)id);
- break;
- case ID_MSK:
- BKE_mask_free(bmain, (Mask *)id);
- break;
- case ID_LS:
- BKE_linestyle_free((FreestyleLineStyle *)id);
- break;
- case ID_PAL:
- BKE_palette_free((Palette *)id);
- break;
- case ID_PC:
- BKE_paint_curve_free((PaintCurve *)id);
- break;
- }
-
- /* avoid notifying on removed data */
- BKE_main_lock(bmain);
-
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
-
- if (free_editor_id_reference_cb) {
- free_editor_id_reference_cb(id);
- }
-
- BLI_remlink(lb, id);
-
- BKE_libblock_free_data(bmain, id);
- BKE_main_unlock(bmain);
-
- MEM_freeN(id);
-}
-
-void BKE_libblock_free(Main *bmain, void *idv)
-{
- BKE_libblock_free_ex(bmain, idv, true);
-}
-
-void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
-{
- ID *id = idv;
-
- id_us_min(id);
-
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
- * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
- * fully unlinked.
- * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
- */
- if ((GS(id->name) == ID_OB) && (id->us == 1)) {
- id_us_clear_real(id);
- }
-
- if (id->us == 0) {
- switch (GS(id->name)) {
- case ID_OB:
- BKE_object_unlink(bmain, (Object *)id);
- break;
- }
-
- BKE_libblock_free(bmain, id);
- }
-}
-
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
new file mode 100644
index 00000000000..daf097b9f0b
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -0,0 +1,176 @@
+/*
+ * ***** 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 *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_idcode.h"
+#include "BKE_library.h"
+#include "BKE_library_idmap.h" /* own include */
+
+/** \file blender/blenkernel/intern/library_idmap.c
+ * \ingroup bke
+ *
+ * Utility functions for faster ID lookups.
+ */
+
+/** \name BKE_main_idmap API
+ *
+ * Cache ID (name, library lookups).
+ * This doesn't account for adding/removing data-blocks,
+ * and should only be used when performing many lookups.
+ *
+ * \note GHash's are initialized on demand,
+ * since its likely some types will never have lookups run on them,
+ * so its a waste to create and never use.
+ * \{ */
+
+struct IDNameLib_Key {
+ /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */
+ const char *name;
+ /** ``ID.lib``: */
+ const Library *lib;
+};
+
+struct IDNameLib_TypeMap {
+ GHash *map;
+ short id_type;
+ /* only for storage of keys in the ghash, avoid many single allocs */
+ struct IDNameLib_Key *keys;
+};
+
+/**
+ * Opaque structure, external API users only see this.
+ */
+struct IDNameLib_Map {
+ struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
+ struct Main *bmain;
+};
+
+static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
+{
+ for (int i = 0; i < MAX_LIBARRAY; i++) {
+ if (id_map->type_maps[i].id_type == id_type) {
+ return &id_map->type_maps[i];
+ }
+ }
+ return NULL;
+}
+
+struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain)
+{
+ struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
+
+ int index = 0;
+ while (index < MAX_LIBARRAY) {
+ struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
+ type_map->map = NULL;
+ type_map->id_type = BKE_idcode_iter_step(&index);
+ BLI_assert(type_map->id_type != 0);
+ }
+ BLI_assert(index == MAX_LIBARRAY);
+
+ id_map->bmain = bmain;
+
+ return id_map;
+}
+
+struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
+{
+ return id_map->bmain;
+}
+
+static unsigned int idkey_hash(const void *ptr)
+{
+ const struct IDNameLib_Key *idkey = ptr;
+ unsigned int key = BLI_ghashutil_strhash(idkey->name);
+ if (idkey->lib) {
+ key ^= BLI_ghashutil_ptrhash(idkey->lib);
+ }
+ return key;
+}
+
+static bool idkey_cmp(const void *a, const void *b)
+{
+ const struct IDNameLib_Key *idkey_a = a;
+ const struct IDNameLib_Key *idkey_b = b;
+ return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
+}
+
+ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
+{
+ struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
+
+ if (UNLIKELY(type_map == NULL)) {
+ return NULL;
+ }
+
+ /* lazy init */
+ if (type_map->map == NULL) {
+ ListBase *lb = which_libbase(id_map->bmain, id_type);
+ const int lb_len = BLI_listbase_count(lb);
+ if (lb_len == 0) {
+ return NULL;
+ }
+ type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
+ type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
+
+ GHash *map = type_map->map;
+ struct IDNameLib_Key *key = type_map->keys;
+
+ for (ID *id = lb->first; id; id = id->next, key++) {
+ key->name = id->name + 2;
+ key->lib = id->lib;
+ BLI_ghash_insert(map, key, id);
+ }
+ }
+
+ const struct IDNameLib_Key key_lookup = {name, lib};
+ return BLI_ghash_lookup(type_map->map, &key_lookup);
+}
+
+ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
+{
+ return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib);
+}
+
+void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
+{
+ struct IDNameLib_TypeMap *type_map = id_map->type_maps;
+ for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
+ if (type_map->map) {
+ BLI_ghash_free(type_map->map, NULL, NULL);
+ type_map->map = NULL;
+ MEM_freeN(type_map->keys);
+ }
+ }
+
+ MEM_freeN(id_map);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index d29d2191602..ebbbf1eb974 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
@@ -61,6 +62,7 @@
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_ghash.h"
#include "BLI_linklist_stack.h"
@@ -69,6 +71,7 @@
#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
@@ -198,9 +201,24 @@ static void library_foreach_actuatorsObjectLooper(
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
+{
+ NlaStrip *substrip;
+
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+
+ for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
+ library_foreach_nla_strip(data, substrip);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
{
FCurve *fcu;
+ NlaTrack *nla_track;
+ NlaStrip *nla_strip;
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
ChannelDriver *driver = fcu->driver;
@@ -216,6 +234,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
}
}
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+
+ for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
+ for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
+ library_foreach_nla_strip(data, nla_strip);
+ }
+ }
+
FOREACH_FINALIZE_VOID;
}
@@ -227,6 +254,14 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
+{
+ FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER);
+
+ FOREACH_FINALIZE_VOID;
+}
+
/**
* Loop over all of the ID's this datablock links to.
@@ -268,6 +303,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
switch (GS(id->name)) {
+ case ID_LI:
+ {
+ Library *lib = (Library *) id;
+ CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ break;
+ }
case ID_SCE:
{
Scene *scene = (Scene *) id;
@@ -278,8 +319,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
CALLBACK_INVOKE(scene->world, IDWALK_USER);
CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- CALLBACK_INVOKE(scene->clip, IDWALK_NOP);
- CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_USER);
+ if (scene->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag);
+ }
/* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
* since basact is just a pointer to one of those items. */
CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
@@ -318,6 +362,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(seq->clip, IDWALK_USER);
CALLBACK_INVOKE(seq->mask, IDWALK_USER);
CALLBACK_INVOKE(seq->sound, IDWALK_USER);
+ for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_USER);
+ }
}
SEQ_END
}
@@ -330,28 +377,28 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (toolsett) {
CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+
CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP);
CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP);
CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP);
+
+ library_foreach_paint(&data, &toolsett->imapaint.paint);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER);
+
if (toolsett->vpaint) {
- CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->vpaint->paint);
}
if (toolsett->wpaint) {
- CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->wpaint->paint);
}
if (toolsett->sculpt) {
- CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->sculpt->paint);
CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
}
if (toolsett->uvsculpt) {
- CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
}
@@ -398,6 +445,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
}
+ /* Note that ob->effect is deprecated, so no need to handle it here. */
if (object->pose) {
bPoseChannel *pchan;
@@ -419,6 +467,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
}
+ CALLBACK_INVOKE(object->probe, IDWALK_NOP);
+ CALLBACK_INVOKE(object->parallaxcorrect, IDWALK_NOP);
+ CALLBACK_INVOKE(object->reflectionplane, IDWALK_NOP);
+
modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
@@ -426,6 +478,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
}
+ if (object->soft && object->soft->effector_weights) {
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ }
+
BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
@@ -477,7 +533,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, material->mtex[i]);
}
}
- CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
+ if (material->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag);
+ }
CALLBACK_INVOKE(material->group, IDWALK_USER);
break;
}
@@ -485,7 +544,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_TE:
{
Tex *texture = (Tex *) id;
- CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag);
+ }
CALLBACK_INVOKE(texture->ima, IDWALK_USER);
if (texture->env) {
CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
@@ -515,7 +577,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, lamp->mtex[i]);
}
}
- CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag);
+ }
break;
}
@@ -548,7 +613,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, world->mtex[i]);
}
}
- CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag);
+ }
break;
}
@@ -608,6 +676,15 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
}
+ if (psett->pd) {
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
+ }
+ if (psett->pd2) {
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
+ }
+
if (psett->boids) {
BoidState *state;
BoidRule *rule;
@@ -625,7 +702,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
}
}
-
break;
}
@@ -634,16 +710,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MovieClip *clip = (MovieClip *) id;
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
- for (object = tracking->objects.first; object; object = object->next) {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track;
- for (track = tracksbase->first; track; track = track->next) {
+ for (track = tracking->tracks.first; track; track = track->next) {
+ CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ }
+ for (object = tracking->objects.first; object; object = object->next) {
+ for (track = object->tracks.first; track; track = track->next) {
CALLBACK_INVOKE(track->gpd, IDWALK_USER);
}
}
+
+ for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
+ CALLBACK_INVOKE(plane_track->image, IDWALK_USER);
+ }
break;
}
@@ -673,7 +756,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, linestyle->mtex[i]);
}
}
- CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag);
+ }
for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
@@ -742,11 +828,18 @@ typedef struct IDUsersIter {
int count; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
{
IDUsersIter *iter = user_data;
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",
+ 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);
+#endif
iter->count++;
}
@@ -776,3 +869,53 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
return iter.count;
}
+
+
+static int foreach_libblock_check_indirect_usage_callback(
+ void *user_data, ID *UNUSED(id_self), ID **id_p, int UNUSED(cb_flag))
+{
+ IDUsersIter *iter = user_data;
+
+ if (*id_p && (*id_p == iter->id)) {
+ iter->count++;
+ return IDWALK_RET_STOP_ITER;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Check wether given ID is used indirectly (i.e. by another linked ID).
+ */
+bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
+{
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int i = set_listbasepointers(bmain, lb_array);
+
+ iter.id = idv;
+ iter.count = 0;
+ while (i--) {
+ ID *id_curr = lb_array[i]->first;
+
+ for (; id_curr; id_curr = id_curr->next) {
+ if (!id_curr->lib) {
+ continue;
+ }
+
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_check_indirect_usage_callback, &iter, IDWALK_NOP);
+
+ if (iter.count) {
+ break;
+ }
+ }
+ if (iter.count) {
+ break;
+ }
+ }
+
+ return (iter.count != 0);
+}
+
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
new file mode 100644
index 00000000000..81543fad0fe
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -0,0 +1,776 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_remap.c
+ * \ingroup bke
+ *
+ * Contains management of ID's and libraries remap, unlink and free logic.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+/* all types are needed here, in order to do memory operations */
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_speaker_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_brush.h"
+#include "BKE_camera.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_gpencil.h"
+#include "BKE_idprop.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#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_material.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_movieclip.h"
+#include "BKE_mask.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_speaker.h"
+#include "BKE_sound.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_world.h"
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
+
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
+{
+ free_windowmanager_cb = func;
+}
+
+static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
+
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
+{
+ free_notifier_reference_cb = func;
+}
+
+static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
+
+void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
+{
+ remap_editor_id_reference_cb = func;
+}
+
+typedef struct IDRemap {
+ ID *old_id;
+ ID *new_id;
+ ID *id; /* The ID in which we are replacing old_id by new_id usages. */
+ short flag;
+
+ /* 'Output' data. */
+ short status;
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
+} IDRemap;
+
+/* IDRemap->flag enums defined in BKE_library.h */
+
+/* IDRemap->status */
+enum {
+ /* *** Set by callback. *** */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
+};
+
+static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag)
+{
+ IDRemap *id_remap_data = user_data;
+ ID *old_id = id_remap_data->old_id;
+ ID *new_id = id_remap_data->new_id;
+ ID *id = id_remap_data->id;
+
+ if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
+ BLI_assert(!new_id);
+ old_id = *id_p;
+ }
+
+ if (*id_p && (*id_p == old_id)) {
+ const bool is_indirect = (id->lib != NULL);
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too...
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ 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;
+ }
+
+ /* 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)))
+ {
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ }
+ else if (is_never_null || is_proxy || is_obj_editmode) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ BLI_assert(0);
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ if (!is_never_null) {
+ *id_p = new_id;
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_us_min(old_id);
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ if (new_id)
+ new_id->us++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ *
+ * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL).
+ * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL).
+ * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id: the new datablock to replace \a old_id references with (may be NULL).
+ * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
+ */
+static void libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
+{
+ IDRemap id_remap_data;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int i;
+
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = remap_flags;
+ r_id_remap_data->status = 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+ if (id) {
+#ifdef DEBUG_PRINT
+ printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+#endif
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ else {
+ i = set_listbasepointers(bmain, lb_array);
+
+ /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
+ * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
+
+ while (i--) {
+ ID *id_curr = lb_array[i]->first;
+
+ 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;
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ }
+ }
+
+ /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
+ * though, we can always add an option (flag) to control this later if needed. */
+ if (old_id && (old_id->flag & LIB_FAKEUSER)) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ id_us_clear_real(old_id);
+
+ if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
+ new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->tag |= LIB_TAG_EXTERN;
+ }
+
+#ifdef DEBUG_PRINT
+ printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
+ r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
+ r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
+#endif
+}
+
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ */
+void BKE_libblock_remap_locked(
+ Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags)
+{
+ IDRemap id_remap_data;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int skipped_direct, skipped_refcounted;
+
+ BLI_assert(old_id != NULL);
+ 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) {
+ free_notifier_reference_cb(old_id);
+ }
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(old_id, new_id);
+ }
+
+ skipped_direct = id_remap_data.skipped_direct;
+ skipped_refcounted = id_remap_data.skipped_refcounted;
+
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
+ * been incremented for that, we have to decrease once more its user count... unless we had to skip
+ * some 'user_one' cases. */
+ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
+ id_us_min(old_id);
+ old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ }
+
+ BLI_assert(old_id->us - skipped_refcounted >= 0);
+ UNUSED_VARS_NDEBUG(skipped_refcounted);
+
+ if (skipped_direct == 0) {
+ /* old_id is assumed to not be used directly anymore... */
+ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
+ old_id->tag &= ~LIB_TAG_EXTERN;
+ old_id->tag |= LIB_TAG_INDIRECT;
+ }
+ }
+
+ /* 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(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;
+ }
+ }
+ break;
+ }
+ case ID_GR:
+ if (new_id == NULL) { /* 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;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Full rebuild of DAG! */
+ DAG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/**
+ * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \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, const bool do_skip_indirect)
+{
+ 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);
+
+ BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/** Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ * \param us_min_never_null: If \a true and new_id is NULL,
+ * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
+ * (needed when given \a idv is going to be deleted right after being unlinked).
+ */
+/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+/* XXX Arg! Naming... :(
+ * _relink? avoids confusion with _remap, but is confusing with _unlink
+ * _remap_used_ids?
+ * _remap_datablocks?
+ * BKE_id_remap maybe?
+ * ... sigh
+ */
+void BKE_libblock_relink_ex(
+ 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. */
+
+ BLI_assert(id);
+ if (old_id) {
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+ }
+ else {
+ BLI_assert(new_id == NULL);
+ }
+
+ libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
+}
+
+static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
+{
+ ChannelDriver *driver;
+ FCurve *fcu;
+
+ /* find the driver this belongs to and update it */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ driver = fcu->driver;
+
+ if (driver) {
+ DriverVar *dvar;
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == userdata)
+ dtar->id = NULL;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+ }
+ }
+}
+
+void BKE_libblock_free_data(Main *bmain, ID *id)
+{
+ if (id->properties) {
+ IDP_FreeProperty(id->properties);
+ MEM_freeN(id->properties);
+ }
+
+ /* this ID may be a driver target! */
+ BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
+}
+
+/**
+ * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+ *
+ * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ */
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+{
+ ID *id = idv;
+ short type = GS(id->name);
+ ListBase *lb = which_libbase(bmain, type);
+
+ DAG_id_type_tag(bmain, type);
+
+#ifdef WITH_PYTHON
+ BPY_id_release(id);
+#endif
+
+ if (do_id_user) {
+ BKE_libblock_relink_ex(id, NULL, NULL, true);
+ }
+
+ switch (type) {
+ case ID_SCE:
+ BKE_scene_free((Scene *)id);
+ break;
+ case ID_LI:
+ BKE_library_free((Library *)id);
+ break;
+ case ID_OB:
+ BKE_object_free((Object *)id);
+ break;
+ case ID_ME:
+ BKE_mesh_free((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_free((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_free((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_free((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_free((Tex *)id);
+ break;
+ case ID_IM:
+ BKE_image_free((Image *)id);
+ break;
+ case ID_LT:
+ BKE_lattice_free((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_lamp_free((Lamp *)id);
+ break;
+ case ID_CA:
+ BKE_camera_free((Camera *) id);
+ break;
+ case ID_IP: /* Deprecated. */
+ BKE_ipo_free((Ipo *)id);
+ break;
+ case ID_KE:
+ BKE_key_free((Key *)id);
+ break;
+ case ID_WO:
+ BKE_world_free((World *)id);
+ break;
+ case ID_SCR:
+ BKE_screen_free((bScreen *)id);
+ break;
+ case ID_VF:
+ BKE_vfont_free((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_free((Text *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_free((Speaker *)id);
+ break;
+ case ID_SO:
+ BKE_sound_free((bSound *)id);
+ break;
+ case ID_GR:
+ BKE_group_free((Group *)id);
+ break;
+ case ID_AR:
+ BKE_armature_free((bArmature *)id);
+ break;
+ case ID_AC:
+ BKE_action_free((bAction *)id);
+ break;
+ case ID_NT:
+ ntreeFreeTree((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_free((Brush *)id);
+ break;
+ case ID_PA:
+ BKE_particlesettings_free((ParticleSettings *)id);
+ break;
+ case ID_WM:
+ if (free_windowmanager_cb)
+ free_windowmanager_cb(NULL, (wmWindowManager *)id);
+ break;
+ case ID_GD:
+ BKE_gpencil_free((bGPdata *)id);
+ break;
+ case ID_MC:
+ BKE_movieclip_free((MovieClip *)id);
+ break;
+ case ID_MSK:
+ BKE_mask_free((Mask *)id);
+ break;
+ case ID_LS:
+ BKE_linestyle_free((FreestyleLineStyle *)id);
+ break;
+ case ID_PAL:
+ BKE_palette_free((Palette *)id);
+ break;
+ case ID_PC:
+ BKE_paint_curve_free((PaintCurve *)id);
+ break;
+ }
+
+ /* avoid notifying on removed data */
+ BKE_main_lock(bmain);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
+
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
+
+ BLI_remlink(lb, id);
+
+ BKE_libblock_free_data(bmain, id);
+ BKE_main_unlock(bmain);
+
+ MEM_freeN(id);
+}
+
+void BKE_libblock_free(Main *bmain, void *idv)
+{
+ BKE_libblock_free_ex(bmain, idv, true);
+}
+
+void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
+{
+ ID *id = idv;
+
+ id_us_min(id);
+
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
+ * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
+ * fully unlinked.
+ * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
+ */
+ if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ id_us_clear_real(id);
+ }
+
+ if (id->us == 0) {
+ BKE_libblock_unlink(bmain, id, false, false);
+
+ BKE_libblock_free(bmain, id);
+ }
+}
+
+void BKE_libblock_delete(Main *bmain, void *idv)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* First tag all datablocks directly from target lib.
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ /* Note: in case we delete a library, we also delete all its datablocks! */
+ if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) {
+ id->tag |= LIB_TAG_DOIT;
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+
+ /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
+ * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
+ * over meshes when we come to freeing obdata). */
+ for (i = base_count; i--; ) {
+ ListBase *lb = lbarray[i];
+ ID *id, *id_next;
+
+ for (id = lb->first; id; id = id_next) {
+ id_next = id->next;
+ if (id->tag & LIB_TAG_DOIT) {
+ if (id->us != 0) {
+#ifdef DEBUG_PRINT
+ printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
+#endif
+ BLI_assert(id->us == 0);
+ }
+ BKE_libblock_free(bmain, id);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 5a1dfc04045..30dc48819e9 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
return linestyle;
}
+/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */
void BKE_linestyle_free(FreestyleLineStyle *linestyle)
{
LineStyleModifier *m;
-
- MTex *mtex;
int a;
+ BKE_animdata_free(&linestyle->id, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(linestyle->mtex[a]);
}
+
+ /* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
ntreeFreeTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
+ linestyle->nodetree = NULL;
}
- BKE_animdata_free(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
@@ -1452,33 +1451,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand
return NULL;
}
-void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob)
-{
- LineStyleModifier *m;
-
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
-}
-
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes)
{
if (use_shading_nodes) {
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 930a3c487ec..94e53755ac4 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -1010,63 +1010,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers)
}
}
-/** free for temp copy, but don't manage unlinking from other pointers */
-void BKE_mask_free_nolib(Mask *mask)
+/** Free (or release) any data used by this mask (does not free the mask itself). */
+void BKE_mask_free(Mask *mask)
{
- BKE_mask_layer_free_list(&mask->masklayers);
-}
-
-void BKE_mask_free(Main *bmain, Mask *mask)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *scene;
-
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- switch (sl->spacetype) {
- case SPACE_CLIP:
- {
- SpaceClip *sc = (SpaceClip *)sl;
-
- if (sc->mask_info.mask == mask) {
- sc->mask_info.mask = NULL;
- }
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (sima->mask_info.mask == mask) {
- sima->mask_info.mask = NULL;
- }
- break;
- }
- }
- }
- }
- }
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (scene->ed) {
- Sequence *seq;
-
- SEQ_BEGIN (scene->ed, seq)
- {
- if (seq->mask == mask) {
- seq->mask = NULL;
- }
- }
- SEQ_END
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)mask, ntree);
- } FOREACH_NODETREE_END
+ BKE_animdata_free((ID *)mask, false);
/* free mask data */
BKE_mask_layer_free_list(&mask->masklayers);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 30f82a50ed9..db5ac54ada9 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -81,47 +81,33 @@ void init_def_material(void)
BKE_material_init(&defmaterial);
}
-/* not material itself */
+/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- BKE_material_free_ex(ma, true);
-}
-
-/* not material itself */
-void BKE_material_free_ex(Material *ma, bool do_id_user)
-{
- MTex *mtex;
int a;
+
+ BKE_animdata_free((ID *)ma, false);
for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(ma->mtex[a]);
}
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
-
- BKE_animdata_free((ID *)ma);
-
- if (ma->preview)
- BKE_previewimg_free(&ma->preview);
- BKE_icon_id_delete((struct ID *)ma);
- ma->id.icon_id = 0;
+ MEM_SAFE_FREE(ma->ramp_col);
+ MEM_SAFE_FREE(ma->ramp_spec);
/* is no lib link block, but material extension */
if (ma->nodetree) {
- ntreeFreeTree_ex(ma->nodetree, do_id_user);
+ ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
+ ma->nodetree = NULL;
}
- if (ma->texpaintslot)
- MEM_freeN(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->texpaintslot);
+
+ GPU_material_free(&ma->gpumaterial);
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
+ BKE_icon_id_delete((ID *)ma);
+ BKE_previewimg_free(&ma->preview);
}
void BKE_material_init(Material *ma)
@@ -1840,7 +1826,7 @@ void free_matcopybuf(void)
matcopybuf.ramp_spec = NULL;
if (matcopybuf.nodetree) {
- ntreeFreeTree_ex(matcopybuf.nodetree, false);
+ ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
matcopybuf.nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index d7019aa8458..685cd35fc20 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -66,28 +66,13 @@
/* Functions */
-void BKE_mball_unlink(MetaBall *mb)
+/** Free (or release) any data used by this mball (does not free the mball itself). */
+void BKE_mball_free(MetaBall *mb)
{
- int a;
-
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a])
- id_us_min(&mb->mat[a]->id);
- mb->mat[a] = NULL;
- }
-}
+ BKE_animdata_free((ID *)mb, false);
+ MEM_SAFE_FREE(mb->mat);
-/* do not free mball itself */
-void BKE_mball_free(MetaBall *mb)
-{
- BKE_mball_unlink(mb);
-
- if (mb->adt) {
- BKE_animdata_free((ID *)mb);
- mb->adt = NULL;
- }
- if (mb->mat) MEM_freeN(mb->mat);
BLI_freelistN(&mb->elems);
if (mb->disp.first) BKE_displist_free(&mb->disp);
}
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 2af78cca79f..706902ef3cf 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -427,38 +427,10 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
}
}
-/* Note: unlinking is called when me->id.us is 0, question remains how
- * much unlinking of Library data in Mesh should be done... probably
- * we need a more generic method, like the expand() functions in
- * readfile.c */
-
-void BKE_mesh_unlink(Mesh *me)
-{
- int a;
-
- if (me == NULL) return;
-
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a])
- id_us_min(&me->mat[a]->id);
- me->mat[a] = NULL;
- }
- }
-
- if (me->key) {
- id_us_min(&me->key->id);
- }
- me->key = NULL;
-
- if (me->texcomesh) me->texcomesh = NULL;
-}
-
-/* do not free mesh itself */
-void BKE_mesh_free(Mesh *me, int unlink)
+/** Free (or release) any data used by this mesh (does not free the mesh itself). */
+void BKE_mesh_free(Mesh *me)
{
- if (unlink)
- BKE_mesh_unlink(me);
+ BKE_animdata_free(&me->id, false);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@@ -466,16 +438,10 @@ void BKE_mesh_free(Mesh *me, int unlink)
CustomData_free(&me->ldata, me->totloop);
CustomData_free(&me->pdata, me->totpoly);
- if (me->adt) {
- BKE_animdata_free(&me->id);
- me->adt = NULL;
- }
-
- if (me->mat) MEM_freeN(me->mat);
-
- if (me->bb) MEM_freeN(me->bb);
- if (me->mselect) MEM_freeN(me->mselect);
- if (me->edit_btmesh) MEM_freeN(me->edit_btmesh);
+ MEM_SAFE_FREE(me->mat);
+ MEM_SAFE_FREE(me->bb);
+ MEM_SAFE_FREE(me->mselect);
+ MEM_SAFE_FREE(me->edit_btmesh);
}
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
@@ -595,12 +561,14 @@ 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){
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 577a21285f8..1c86fbcfe8e 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -677,7 +677,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
*/
copy_v3_v3(*lnor, polynors[mp_index]);
- /* printf("BASIC: handling loop %d / edge %d / vert %d\n", ml_curr_index, ml_curr->e, ml_curr->v); */
+ /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
@@ -3262,14 +3262,14 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
*/
void BKE_mesh_polygon_flip_ex(
MPoly *mpoly, MLoop *mloop, CustomData *ldata,
- MDisps *mdisp, const bool use_loop_mdisp_flip)
+ float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip)
{
int loopstart = mpoly->loopstart;
int loopend = loopstart + mpoly->totloop - 1;
const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
if (mdisp) {
- for (int i = mpoly->loopstart; i <= loopend; i++) {
+ for (int i = loopstart; i <= loopend; i++) {
BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
}
}
@@ -3288,6 +3288,9 @@ void BKE_mesh_polygon_flip_ex(
if (!loops_in_ldata) {
SWAP(MLoop, mloop[loopstart], mloop[loopend]);
}
+ if (lnors) {
+ swap_v3_v3(lnors[loopstart], lnors[loopend]);
+ }
CustomData_swap(ldata, loopstart, loopend);
}
/* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
@@ -3299,7 +3302,7 @@ void BKE_mesh_polygon_flip_ex(
void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
{
MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
}
/**
@@ -3315,7 +3318,7 @@ void BKE_mesh_polygons_flip(
int i;
for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
- BKE_mesh_polygon_flip_ex(mp, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
}
}
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/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a8d3c600817..f99457a4c26 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -608,7 +608,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name)
return clip;
}
-static void movieclip_load_get_szie(MovieClip *clip)
+static void movieclip_load_get_size(MovieClip *clip)
{
int width, height;
MovieClipUser user = {0};
@@ -670,7 +670,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
detect_clip_source(clip);
- movieclip_load_get_szie(clip);
+ movieclip_load_get_size(clip);
if (clip->lastsize[0]) {
int width = clip->lastsize[0];
@@ -1248,7 +1248,7 @@ static void free_buffers(MovieClip *clip)
clip->anim = NULL;
}
- BKE_animdata_free((ID *) clip);
+ BKE_animdata_free((ID *) clip, false);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
@@ -1276,7 +1276,7 @@ void BKE_movieclip_reload(MovieClip *clip)
detect_clip_source(clip);
clip->lastsize[0] = clip->lastsize[1] = 0;
- movieclip_load_get_szie(clip);
+ movieclip_load_get_size(clip);
movieclip_calc_length(clip);
@@ -1482,80 +1482,15 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru
}
}
+/** Free (or release) any data used by this movie clip (does not free the clip itself). */
void BKE_movieclip_free(MovieClip *clip)
{
+ /* Also frees animdata. */
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
}
-void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *sce;
- Object *ob;
-
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *) sl;
-
- if (sc->clip == clip)
- sc->clip = NULL;
- }
- else if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- BGpic *bgpic;
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->clip == clip)
- bgpic->clip = NULL;
- }
- }
- }
- }
- }
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->clip == clip)
- sce->clip = NULL;
- }
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bConstraint *con;
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)clip, ntree);
- } FOREACH_NODETREE_END
-
- clip->id.us = 0;
-}
-
float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
{
return framenr - (float) clip->start_frame + 1.0f;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 75f899dd597..d78ddc41e97 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1782,21 +1782,21 @@ static void free_localized_node_groups(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP && node->id) {
bNodeTree *ngroup = (bNodeTree *)node->id;
- ntreeFreeTree_ex(ngroup, false);
+ ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
}
}
}
-/* do not free ntree itself here, BKE_libblock_free calls this function too */
-void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
+/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */
+void ntreeFreeTree(bNodeTree *ntree)
{
bNodeTree *tntree;
bNode *node, *next;
bNodeSocket *sock, *nextsock;
-
- if (ntree == NULL) return;
-
+
+ BKE_animdata_free((ID *)ntree, false);
+
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
@@ -1820,29 +1820,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
/* unregister associated RNA types */
ntreeInterfaceTypeFree(ntree);
- BKE_animdata_free((ID *)ntree);
-
- id_us_min((ID *)ntree->gpd);
-
BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
for (node = ntree->nodes.first; node; node = next) {
next = node->next;
-
- /* ntreeUserIncrefID inline */
-
- /* XXX, this is correct, however when freeing the entire database
- * this ends up accessing freed data which isn't properly unlinking
- * its self from scene nodes, SO - for now prefer invalid usercounts
- * on free rather then bad memory access - Campbell */
-#if 0
- if (do_id_user) {
- id_us_min(node->id);
- }
-#else
- (void)do_id_user;
-#endif
-
node_free_node_ex(ntree, node, false, false);
}
@@ -1874,11 +1855,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
BKE_libblock_free_data(G.main, &ntree->id);
}
}
-/* same as ntreeFreeTree_ex but always manage users */
-void ntreeFreeTree(bNodeTree *ntree)
-{
- ntreeFreeTree_ex(ntree, true);
-}
void ntreeFreeCache(bNodeTree *ntree)
{
@@ -2165,7 +2141,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
if (ntree->typeinfo->local_merge)
ntree->typeinfo->local_merge(localtree, ntree);
- ntreeFreeTree_ex(localtree, false);
+ ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
}
@@ -2418,15 +2394,21 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree)
/* ************ find stuff *************** */
+bNode *ntreeFindType(const bNodeTree *ntree, int type)
+{
+ if (ntree) {
+ for (bNode * node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == type) {
+ return node;
+ }
+ }
+ }
+ return NULL;
+}
+
bool ntreeHasType(const bNodeTree *ntree, int type)
{
- bNode *node;
-
- if (ntree)
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->type == type)
- return true;
- return false;
+ return ntreeFindType(ntree, type) != NULL;
}
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e44318c6633..c2d45c6d447 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -213,7 +213,6 @@ void BKE_object_free_modifiers(Object *ob)
/* same for softbody */
BKE_object_free_softbody(ob);
- /* modifiers may have stored data in the DM cache */
BKE_object_free_derived_caches(ob);
}
@@ -318,14 +317,14 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->bb) {
+ if (me && me->bb) {
me->bb->flag |= BOUNDBOX_DIRTY;
}
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
- if (cu->bb) {
+ if (cu && cu->bb) {
cu->bb->flag |= BOUNDBOX_DIRTY;
}
}
@@ -394,78 +393,54 @@ void BKE_object_free_caches(Object *object)
}
}
-/* do not free object itself */
-void BKE_object_free_ex(Object *ob, bool do_id_user)
+/** Free (or release) any data used by this object (does not free the object itself). */
+void BKE_object_free(Object *ob)
{
- int a;
-
+ BKE_animdata_free((ID *)ob, false);
+
BKE_object_free_modifiers(ob);
-
- /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */
- if (ob->data) {
- ID *id = ob->data;
- id_us_min(id);
- if (id->us == 0 && id->lib == NULL) {
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_unlink((Mesh *)id);
- break;
- case OB_CURVE:
- BKE_curve_unlink((Curve *)id);
- break;
- case OB_MBALL:
- BKE_mball_unlink((MetaBall *)id);
- break;
- }
- }
- ob->data = NULL;
- }
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a])
- id_us_min(&ob->mat[a]->id);
- }
- MEM_freeN(ob->mat);
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(ob->iuser);
+ MEM_SAFE_FREE(ob->bb);
+
+ BLI_freelistN(&ob->defbase);
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
}
- if (ob->matbits) MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- if (ob->iuser) MEM_freeN(ob->iuser);
- ob->iuser = NULL;
- if (ob->bb) MEM_freeN(ob->bb);
- ob->bb = NULL;
- if (ob->adt) BKE_animdata_free((ID *)ob);
- if (ob->poselib)
- id_us_min(&ob->poselib->id);
- if (ob->gpd)
- id_us_min(&ob->gpd->id);
- if (ob->defbase.first)
- BLI_freelistN(&ob->defbase);
- if (ob->pose)
- BKE_pose_free_ex(ob->pose, do_id_user);
- if (ob->mpath)
+ if (ob->mpath) {
animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ }
BKE_bproperty_free_list(&ob->prop);
-
+
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
free_actuators(&ob->actuators);
- BKE_constraints_free_ex(&ob->constraints, do_id_user);
+ BKE_constraints_free_ex(&ob->constraints, false);
free_partdeflect(ob->pd);
BKE_rigidbody_free_object(ob);
BKE_rigidbody_free_constraint(ob);
- if (ob->soft) sbFree(ob->soft);
- if (ob->bsoft) bsbFree(ob->bsoft);
- if (ob->gpulamp.first) GPU_lamp_free(ob);
- if (ob->gpuprobe.first) GPU_probe_free(&ob->gpuprobe);
+ if (ob->soft) {
+ sbFree(ob->soft);
+ ob->soft = NULL;
+ }
+ if (ob->bsoft) {
+ bsbFree(ob->bsoft);
+ ob->bsoft = NULL;
+ }
+ GPU_lamp_free(ob);
+
+ GPU_probe_free(&ob->gpuprobe);
BKE_sculptsession_free(ob);
- if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
+ BLI_freelistN(&ob->pc_ids);
BLI_freelistN(&ob->lodlevels);
@@ -475,409 +450,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->curve_cache->path)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
+ ob->curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
}
-void BKE_object_free(Object *ob)
-{
- BKE_object_free_ex(ob, true);
-}
-
-static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag))
-{
- Object *unlinkOb = userData;
-
- if (*obpoin == unlinkOb) {
- *obpoin = NULL;
- // XXX: should this just be OB_RECALC_DATA?
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-}
-
-void BKE_object_unlink(Main *bmain, Object *ob)
-{
- Object *obt;
- Material *mat;
- World *wrld;
- bScreen *sc;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleLineSet *lineset;
- bNodeTree *ntree;
- Curve *cu;
- Tex *tex;
- Group *group;
- Camera *camera;
- bConstraint *con;
- //bActionStrip *strip; // XXX animsys
- ModifierData *md;
- ARegion *ar;
- RegionView3D *rv3d;
- LodLevel *lod;
- int a, found;
-
- unlink_controllers(&ob->controllers);
- unlink_actuators(&ob->actuators);
-
- /* check all objects: parents en bevels and fields, also from libraries */
- /* FIXME: need to check all animation blocks (drivers) */
- obt = bmain->object.first;
- while (obt) {
- if (obt->proxy == ob)
- obt->proxy = NULL;
- if (obt->proxy_from == ob) {
- obt->proxy_from = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB);
- }
- if (obt->proxy_group == ob)
- obt->proxy_group = NULL;
-
- if (obt->parent == ob) {
- obt->parent = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-
- modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob);
-
- if (ELEM(obt->type, OB_CURVE, OB_FONT)) {
- cu = obt->data;
-
- if (cu->bevobj == ob) {
- cu->bevobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->taperobj == ob) {
- cu->taperobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->textoncurve == ob) {
- cu->textoncurve = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- }
- else if (obt->type == OB_ARMATURE && obt->pose) {
- bPoseChannel *pchan;
- for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- ct->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- if (pchan->custom == ob)
- pchan->custom = NULL;
- }
- }
- else if (ELEM(OB_MBALL, ob->type, obt->type)) {
- if (BKE_mball_is_basis_for(obt, ob))
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- sca_remove_ob_poin(obt, ob);
-
- for (con = obt->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- ct->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
-
- /* object is deflector or field */
- if (ob->pd) {
- if (obt->soft)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
-
- /* cloth */
- for (md = obt->modifiers.first; md; md = md->next)
- if (md->type == eModifierType_Cloth)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* strips */
-#if 0 // XXX old animation system
- for (strip = obt->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == ob)
- strip->object = NULL;
-
- if (strip->modifiers.first) {
- bActionModifier *amod;
- for (amod = strip->modifiers.first; amod; amod = amod->next)
- if (amod->ob == ob)
- amod->ob = NULL;
- }
- }
-#endif // XXX old animation system
-
- /* particle systems */
- if (obt->particlesystem.first) {
- ParticleSystem *tpsys = obt->particlesystem.first;
- for (; tpsys; tpsys = tpsys->next) {
- BoidState *state = NULL;
- BoidRule *rule = NULL;
-
- ParticleTarget *pt = tpsys->targets.first;
- for (; pt; pt = pt->next) {
- if (pt->ob == ob) {
- pt->ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- break;
- }
- }
-
- if (tpsys->target_ob == ob) {
- tpsys->target_ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- if (tpsys->part->dup_ob == ob)
- tpsys->part->dup_ob = NULL;
-
- if (tpsys->part->phystype == PART_PHYS_BOIDS) {
- ParticleData *pa;
- BoidParticle *bpa;
- int p;
-
- for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) {
- bpa = pa->boid;
- if (bpa->ground == ob)
- bpa->ground = NULL;
- }
- }
- if (tpsys->part->boids) {
- for (state = tpsys->part->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- if (gabr->ob == ob)
- gabr->ob = NULL;
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- if (flbr->ob == ob)
- flbr->ob = NULL;
- }
- }
- }
- }
-
- if (tpsys->parent == ob)
- tpsys->parent = NULL;
- }
- if (ob->pd)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* levels of detail */
- for (lod = obt->lodlevels.first; lod; lod = lod->next) {
- if (lod->source == ob)
- lod->source = NULL;
- }
-
- /* probe */
- if (obt->probe == ob)
- ob->probe = NULL;
-
- if (obt->parallaxcorrect == ob)
- ob->parallaxcorrect = NULL;
-
- if (obt->reflectionplane == ob)
- ob->reflectionplane = NULL;
-
- obt = obt->id.next;
-
- }
-
- /* materials */
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- if (mat->nodetree) {
- ntreeSwitchID(mat->nodetree, &ob->id, NULL);
- }
- for (a = 0; a < MAX_MTEX; a++) {
- if (mat->mtex[a] && ob == mat->mtex[a]->object) {
- /* actually, test for lib here... to do */
- mat->mtex[a]->object = NULL;
- }
- }
- }
-
- /* node trees */
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->type == NTREE_SHADER)
- ntreeSwitchID(ntree, &ob->id, NULL);
- }
-
- /* textures */
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->env && (ob == tex->env->object)) tex->env->object = NULL;
- if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL;
- if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL;
- }
-
- /* worlds */
- wrld = bmain->world.first;
- while (wrld) {
- if (wrld->id.lib == NULL) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && ob == wrld->mtex[a]->object)
- wrld->mtex[a]->object = NULL;
- }
- }
-
- wrld = wrld->id.next;
- }
-
- /* scenes */
- sce = bmain->scene.first;
- while (sce) {
- if (sce->id.lib == NULL) {
- if (sce->camera == ob) sce->camera = NULL;
- if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL;
- if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL;
- if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL;
-
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *m;
-
- for (m = sce->markers.first; m; m = m->next) {
- if (m->camera == ob)
- m->camera = NULL;
- }
- }
-#endif
- if (sce->ed) {
- Sequence *seq;
- SEQ_BEGIN(sce->ed, seq)
- {
- if (seq->scene_camera == ob) {
- seq->scene_camera = NULL;
- }
- }
- SEQ_END
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
- lineset; lineset = lineset->next)
- {
- if (lineset->linestyle) {
- BKE_linestyle_target_object_unlink(lineset->linestyle, ob);
- }
- }
- }
- }
-
- sce = sce->id.next;
- }
-
- /* screens */
- sc = bmain->screen.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
-
- /* found doesn't need to be set here */
- if (v3d->ob_centre == ob) {
- v3d->ob_centre = NULL;
- v3d->ob_centre_bone[0] = '\0';
- }
- if (v3d->localvd && v3d->localvd->ob_centre == ob) {
- v3d->localvd->ob_centre = NULL;
- v3d->localvd->ob_centre_bone[0] = '\0';
- }
-
- found = 0;
- if (v3d->camera == ob) {
- v3d->camera = NULL;
- found = 1;
- }
- if (v3d->localvd && v3d->localvd->camera == ob) {
- v3d->localvd->camera = NULL;
- found += 2;
- }
-
- if (found) {
- if (sa->spacetype == SPACE_VIEW3D) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- rv3d = (RegionView3D *)ar->regiondata;
- if (found == 1 || found == 3) {
- if (rv3d->persp == RV3D_CAMOB)
- rv3d->persp = RV3D_PERSP;
- }
- if (found == 2 || found == 3) {
- if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB)
- rv3d->localvd->persp = RV3D_PERSP;
- }
- }
- }
- }
- }
- }
-#if 0
- else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
- /* now handled by WM_main_remove_editor_id_reference */
- }
-#endif
- }
-
- sa = sa->next;
- }
- sc = sc->id.next;
- }
-
- /* groups */
- group = bmain->group.first;
- while (group) {
- BKE_group_object_unlink(group, ob, NULL, NULL);
- group = group->id.next;
- }
-
- /* cameras */
- camera = bmain->camera.first;
- while (camera) {
- if (camera->dof_ob == ob) {
- camera->dof_ob = NULL;
- }
- camera = camera->id.next;
- }
-}
-
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(Object *ob)
{
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 63c37fddc60..c03f7c2c0ae 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -851,7 +851,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part == NULL)
return;
- if (!psys_check_enabled(par, psys))
+ if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
return;
if (!for_render)
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 03348adeabc..6d41c5c2975 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -269,7 +269,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
psys_changed_type(ob, psys);
}
- if (psys_check_enabled(ob, psys)) {
+ if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
/* check use of dupli objects here */
if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
@@ -278,7 +278,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
ob->transflag |= OB_DUPLIPARTS;
}
- particle_system_update(scene, ob, psys);
+ particle_system_update(scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
@@ -347,3 +347,10 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 3a2663c5d48..8c1502643c5 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
}
}
+/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
void BKE_paint_curve_free(PaintCurve *pc)
{
- if (pc->points) {
- MEM_freeN(pc->points);
- pc->points = NULL;
- pc->tot_points = 0;
- }
+ MEM_SAFE_FREE(pc->points);
+ pc->tot_points = 0;
}
PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
@@ -378,6 +376,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
+/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
BLI_freelistN(&palette->colors);
@@ -493,8 +492,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3])
void BKE_paint_free(Paint *paint)
{
- id_us_min((ID *)paint->brush);
- id_us_min((ID *)paint->palette);
curvemapping_free(paint->cavity_curve);
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 25dd7fff380..d1f5afa26a6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -283,7 +283,7 @@ bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
{
return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
}
-bool psys_check_enabled(Object *ob, ParticleSystem *psys)
+bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSystemModifierData *psmd;
@@ -291,7 +291,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys)
return 0;
psmd = psys_get_modifier(ob, psys);
- if (psys->renderdata || G.is_rendering) {
+ if (psys->renderdata || use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -376,12 +376,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid)
MEM_freeN(fluid);
}
+/** Free (or release) any data used by this particle settings (does not free the partsett itself). */
void BKE_particlesettings_free(ParticleSettings *part)
{
- MTex *mtex;
int a;
- BKE_animdata_free(&part->id);
+
+ BKE_animdata_free((ID *)part, false);
+ for (a = 0; a < MAX_MTEX; a++) {
+ MEM_SAFE_FREE(part->mtex[a]);
+ }
+
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
if (part->roughcurve)
@@ -390,21 +395,12 @@ void BKE_particlesettings_free(ParticleSettings *part)
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
- if (part->effector_weights)
- MEM_freeN(part->effector_weights);
+ MEM_SAFE_FREE(part->effector_weights);
BLI_freelistN(&part->dupliweights);
boid_free_settings(part->boids);
fluid_free_settings(part->fluid);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = part->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
}
void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
@@ -573,10 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (!nr)
ob->transflag &= ~OB_DUPLIPARTS;
- if (psys->part) {
- id_us_min(&psys->part->id);
- psys->part = NULL;
- }
+ psys->part = NULL;
BKE_ptcache_free_list(&psys->ptcaches);
psys->pointcache = NULL;
@@ -2014,7 +2007,7 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
return vg;
}
-void psys_find_parents(ParticleSimulationData *sim)
+void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = sim->psys->part;
@@ -2026,7 +2019,7 @@ void psys_find_parents(ParticleSimulationData *sim)
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if ((sim->psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr)
+ if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* hard limit, workaround for it being ignored above */
@@ -2057,7 +2050,9 @@ void psys_find_parents(ParticleSimulationData *sim)
BLI_kdtree_free(tree);
}
-static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate)
+static bool psys_thread_context_init_path(
+ ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene,
+ float cfra, const bool editupdate, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -2071,7 +2066,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys_in_edit_mode(scene, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2080,14 +2075,14 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if ((psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr)
+ if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* part->parents could still be 0 so we can't test with totparent */
between = 1;
}
- if (psys->renderdata || G.is_rendering)
+ if (psys->renderdata || use_render_params)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2424,7 +2419,9 @@ static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *task
}
}
-void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate)
+void psys_cache_child_paths(
+ ParticleSimulationData *sim, float cfra,
+ const bool editupdate, const bool use_render_params)
{
TaskScheduler *task_scheduler;
TaskPool *task_pool;
@@ -2437,7 +2434,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
return;
/* create a task pool for child path tasks */
- if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate))
+ if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params))
return;
task_scheduler = BLI_task_scheduler_get();
@@ -2529,7 +2526,7 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache
* - Useful for making use of opengl vertex arrays for super fast strand drawing.
* - Makes child strands possible and creates them too into the cache.
* - Cached path data is also used to determine cut position for the editmode tool. */
-void psys_cache_paths(ParticleSimulationData *sim, float cfra)
+void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
PARTICLE_PSMD;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
@@ -2553,7 +2550,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2732,7 +2729,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if (vg_length)
MEM_freeN(vg_length);
}
-void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra)
+void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
{
ParticleCacheKey *ca, **cache = edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
@@ -2928,7 +2925,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
sim.psys = psys;
sim.psmd = psys_get_modifier(ob, psys);
- psys_cache_child_paths(&sim, cfra, 1);
+ psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
/* clear recalc flag if set here */
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index f6bddfa6f99..c814713f3f4 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -392,22 +392,25 @@ static int distribute_binary_search(float *sum, int n, float value)
{
int mid, low = 0, high = n - 1;
+ if (high == low)
+ return low;
+
if (sum[low] >= value)
return low;
- if (sum[high] < value)
+ if (sum[high - 1] < value)
return high;
while (low < high) {
mid = (low + high) / 2;
- if ((sum[mid] < value) && (sum[mid + 1] >= value))
+ if ((sum[mid] >= value) && (sum[mid - 1] < value))
return mid;
- if (sum[mid] >= value) {
+ if (sum[mid] > value) {
high = mid - 1;
}
- else if (sum[mid] < value) {
+ else {
low = mid + 1;
}
}
@@ -1004,56 +1007,62 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
MEM_freeN(vweight);
}
+#define MIN_WEIGHT 1e-7f /* Weights too small cause issues e.g. with binary search... */
+
/* Calculate total weight of all elements */
int totmapped = 0;
totweight = 0.0f;
for (i = 0; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > MIN_WEIGHT) {
totmapped++;
+ totweight += element_weight[i];
}
- totweight += element_weight[i];
}
- if (totweight == 0.0f) {
+ if (totmapped == 0) {
/* We are not allowed to distribute particles anywhere... */
return 0;
}
- inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
+ inv_totweight = 1.0f / totweight;
/* Calculate cumulative weights.
* We remove all null-weighted elements from element_sum, and create a new mapping
* 'activ'_elem_index -> orig_elem_index.
- * This simplifies greatly the filtering of zero-weighted items - and can be much mor efficient
+ * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient
* especially in random case (reducing a lot the size of binary-searched array)...
*/
float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__);
int i_mapped = 0;
- for (i = 0; i < totelem && element_weight[i] == 0.0f; i++);
+ for (i = 0; i < totelem && element_weight[i] <= MIN_WEIGHT; i++);
element_sum[i_mapped] = element_weight[i] * inv_totweight;
element_map[i_mapped] = i;
i_mapped++;
for (i++; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > MIN_WEIGHT) {
element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
+ BLI_assert(element_sum[i_mapped] > element_sum[i_mapped - 1]);
element_map[i_mapped] = i;
i_mapped++;
}
}
BLI_assert(i_mapped == totmapped);
-
+
+#undef MIN_WEIGHT
+
/* Finally assign elements to particles */
if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
- float pos;
-
for (p = 0; p < totpart; p++) {
- /* In theory element_sum[totelem - 1] should be 1.0,
+ /* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos = BLI_frand() * element_sum[totmapped - 1];
- particle_element[p] = element_map[distribute_binary_search(element_sum, totmapped, pos)];
+ const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const int eidx = distribute_binary_search(element_sum, totmapped, pos);
+ particle_element[p] = element_map[eidx];
+ BLI_assert(pos <= element_sum[eidx]);
+ BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f));
jitter_offset[particle_element[p]] = pos;
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 1ca68f714c8..c3f47fac852 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -230,7 +230,7 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles");
if (newboids == NULL) {
- /* allocation error! */
+ /* allocation error! */
if (newpars)
MEM_freeN(newpars);
return;
@@ -2885,7 +2885,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
/* Hair */
/************************************************/
/* check if path cache or children need updating and do it if needed */
-static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
+static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -2909,7 +2909,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
distribute_particles(sim, PART_FROM_CHILD);
if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f)
- psys_find_parents(sim);
+ psys_find_parents(sim, use_render_params);
}
}
else
@@ -2947,7 +2947,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
}
if (!skip) {
- psys_cache_paths(sim, cfra);
+ psys_cache_paths(sim, cfra, use_render_params);
/* for render, child particle paths are computed on the fly */
if (part->childtype) {
@@ -2957,7 +2957,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
skip = 1;
if (!skip)
- psys_cache_child_paths(sim, cfra, 0);
+ psys_cache_child_paths(sim, cfra, 0, use_render_params);
}
}
else if (psys->pathcache)
@@ -3193,7 +3193,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
/* restore cloth effector weights */
psys->clmd->sim_parms->effector_weights = clmd_effweights;
}
-static void hair_step(ParticleSimulationData *sim, float cfra)
+static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3225,7 +3225,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
/* following lines were removed r29079 but cause bug [#22811], see report for details */
psys_update_effectors(sim);
- psys_update_path_cache(sim, cfra);
+ psys_update_path_cache(sim, cfra, use_render_params);
psys->flag |= PSYS_HAIR_UPDATED;
}
@@ -3732,7 +3732,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
}
}
-static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
+static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
if (psys->particles) {
@@ -3775,7 +3775,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
}
gzread(gzf, &totpart, sizeof(totpart));
- totpart = (G.is_rendering)?totpart:(part->disp*totpart) / 100;
+ totpart = (use_render_params) ? totpart:(part->disp*totpart) / 100;
part->totpart= totpart;
part->sta=part->end = 1.0f;
@@ -3836,6 +3836,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
} // fluid sim particles done
}
+#else
+ UNUSED_VARS(use_render_params);
#endif // WITH_MOD_FLUID
}
@@ -3857,7 +3859,7 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU
* 2. Check cache (if used) and return if frame is cached
* 3. Do dynamics
* 4. Save to cache */
-static void system_step(ParticleSimulationData *sim, float cfra)
+static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3919,7 +3921,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
cached_step(sim, cfra);
update_children(sim);
- psys_update_path_cache(sim, cfra);
+ psys_update_path_cache(sim, cfra, use_render_params);
BKE_ptcache_validate(cache, (int)cache_cfra);
@@ -4137,7 +4139,7 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
+void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
@@ -4146,7 +4148,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
/* drawdata is outdated after ANY change */
if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, use_render_params))
return;
cfra= BKE_scene_frame_get(scene);
@@ -4215,7 +4217,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
hcfra=100.0f*(float)i/(float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW)==0)
BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
- system_step(&sim, hcfra);
+ system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
psys->recalc = 0;
save_hair(&sim, hcfra);
@@ -4228,12 +4230,12 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_HAIR_DONE;
if (psys->flag & PSYS_HAIR_DONE)
- hair_step(&sim, cfra);
+ hair_step(&sim, cfra, use_render_params);
break;
}
case PART_FLUID:
{
- particles_fluid_step(&sim, (int)cfra);
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
break;
}
default:
@@ -4280,14 +4282,14 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
if (part->phystype == PART_PHYS_KEYED) {
psys_count_keyed_targets(&sim);
set_keyed_keys(&sim);
- psys_update_path_cache(&sim,(int)cfra);
+ psys_update_path_cache(&sim, (int)cfra, use_render_params);
}
break;
}
default:
{
/* the main dynamic particle system step */
- system_step(&sim, cfra);
+ system_step(&sim, cfra, use_render_params);
break;
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 88dc63d6cb2..87d22d01275 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1909,17 +1909,22 @@ 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_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 +1941,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;
+ 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);
#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
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index f0ba63e35b4..e0a3e9743db 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -55,8 +55,6 @@
#include "PIL_time.h"
-#include "WM_api.h"
-
#include "BKE_appdir.h"
#include "BKE_anim.h"
#include "BKE_cloth.h"
@@ -2501,7 +2499,7 @@ static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra)
#ifdef WITH_OPENVDB
char filename[FILE_MAX * 2];
- /* save blend file before using disk pointcache */
+ /* save blend file before using disk pointcache */
if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
return 0;
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index e90a39e8c0e..a468420f87d 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -653,77 +653,6 @@ void set_sca_new_poins(void)
}
}
-void sca_remove_ob_poin(Object *obt, Object *ob)
-{
- bSensor *sens;
- bMessageSensor *ms;
- bActuator *act;
- bCameraActuator *ca;
- bObjectActuator *oa;
- bSceneActuator *sa;
- bEditObjectActuator *eoa;
- bPropertyActuator *pa;
- bMessageActuator *ma;
- bParentActuator *para;
- bArmatureActuator *aa;
- bSteeringActuator *sta;
-
-
- sens= obt->sensors.first;
- while (sens) {
- switch (sens->type) {
- case SENS_MESSAGE:
- ms= sens->data;
- if (ms->fromObject==ob) ms->fromObject= NULL;
- }
- sens= sens->next;
- }
-
- act= obt->actuators.first;
- while (act) {
- switch (act->type) {
- case ACT_CAMERA:
- ca= act->data;
- if (ca->ob==ob) ca->ob= NULL;
- break;
- case ACT_OBJECT:
- oa= act->data;
- if (oa->reference==ob) oa->reference= NULL;
- break;
- case ACT_PROPERTY:
- pa= act->data;
- if (pa->ob==ob) pa->ob= NULL;
- break;
- case ACT_SCENE:
- sa= act->data;
- if (sa->camera==ob) sa->camera= NULL;
- break;
- case ACT_EDIT_OBJECT:
- eoa= act->data;
- if (eoa->ob==ob) eoa->ob= NULL;
- break;
- case ACT_MESSAGE:
- ma= act->data;
- if (ma->toObject==ob) ma->toObject= NULL;
- break;
- case ACT_PARENT:
- para = act->data;
- if (para->ob==ob) para->ob = NULL;
- break;
- case ACT_ARMATURE:
- aa = act->data;
- if (aa->target == ob) aa->target = NULL;
- if (aa->subtarget == ob) aa->subtarget = NULL;
- break;
- case ACT_STEERING:
- sta = act->data;
- if (sta->navmesh == ob) sta->navmesh = NULL;
- if (sta->target == ob) sta->target = NULL;
- }
- act= act->next;
- }
-}
-
/* ******************** INTERFACE ******************* */
void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up)
{
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index d307ba1811b..0e8efca04d0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -357,41 +357,34 @@ void BKE_scene_groups_relink(Scene *sce)
BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
-/* do not free scene itself */
+/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free(Scene *sce)
{
- Base *base;
SceneRenderLayer *srl;
+ BKE_animdata_free((ID *)sce, false);
+
/* check all sequences */
BKE_sequencer_clear_scene_in_allseqs(G.main, sce);
- base = sce->base.first;
- while (base) {
- id_us_min(&base->object->id);
- base = base->next;
- }
- /* do not free objects! */
-
- if (sce->gpd) {
-#if 0 /* removed since this can be invalid memory when freeing everything */
- /* since the grease pencil data is freed before the scene.
- * since grease pencil data is not (yet?), shared between objects
- * its probably safe not to do this, some save and reload will free this. */
- id_us_min(&sce->gpd->id);
-#endif
- sce->gpd = NULL;
- }
-
+ sce->basact = NULL;
BLI_freelistN(&sce->base);
BKE_sequencer_editing_free(sce);
- BKE_animdata_free((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
-
- if (sce->rigidbody_world)
+
+ /* is no lib link block, but scene extension */
+ if (sce->nodetree) {
+ ntreeFreeTree(sce->nodetree);
+ MEM_freeN(sce->nodetree);
+ sce->nodetree = NULL;
+ }
+
+ if (sce->rigidbody_world) {
BKE_rigidbody_free_world(sce->rigidbody_world);
-
+ sce->rigidbody_world = NULL;
+ }
+
if (sce->r.avicodecdata) {
free_avicodecdata(sce->r.avicodecdata);
MEM_freeN(sce->r.avicodecdata);
@@ -444,15 +437,8 @@ void BKE_scene_free(Scene *sce)
if (sce->depsgraph)
DEG_graph_free(sce->depsgraph);
- if (sce->nodetree) {
- ntreeFreeTree(sce->nodetree);
- MEM_freeN(sce->nodetree);
- }
-
- if (sce->stats)
- MEM_freeN(sce->stats);
- if (sce->fps_info)
- MEM_freeN(sce->fps_info);
+ MEM_SAFE_FREE(sce->stats);
+ MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -904,40 +890,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
-{
- Scene *sce1;
- bScreen *screen;
-
- /* check all sets */
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next)
- if (sce1->set == sce)
- sce1->set = NULL;
-
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) {
- bNode *node;
-
- if (sce1 == sce || !sce1->nodetree)
- continue;
-
- for (node = sce1->nodetree->nodes.first; node; node = node->next) {
- if (node->id == &sce->id)
- node->id = NULL;
- }
- }
-
- /* all screens */
- for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- if (screen->scene == sce) {
- screen->scene = newsce;
- }
-
- /* editors are handled by WM_main_remove_editor_id_reference */
- }
-
- BKE_libblock_free(bmain, sce);
-}
-
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
Scene **scene, int val, Base **base, Object **ob)
@@ -1193,6 +1145,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base)
BKE_rigidbody_remove_object(sce, base->object);
BLI_remlink(&sce->base, base);
+ if (sce->basact == base)
+ sce->basact = NULL;
}
void BKE_scene_base_deselect_all(Scene *sce)
@@ -2193,6 +2147,13 @@ bool BKE_scene_use_shading_nodes_custom(Scene *scene)
return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
+bool BKE_scene_use_world_space_shading(Scene *scene)
+{
+ const RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return ((scene->r.mode & R_USE_WS_SHADING) ||
+ (type && (type->flag & RE_USE_SHADING_NODES)));
+}
+
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 139c6670f74..857bd5447c8 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set)
}
}
-static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
{
- spacedata_id_unref_cb = func;
+ spacedata_id_remap_cb = func;
}
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+/* UNUSED!!! */
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
{
- if (spacedata_id_unref_cb) {
- spacedata_id_unref_cb(sl, id);
+ if (spacedata_id_remap_cb) {
+ spacedata_id_remap_cb(sa, sl, id, NULL);
}
}
@@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
-/* don't free screen itself */
+/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
ScrArea *sa, *san;
ARegion *ar;
+
+ /* No animdata here. */
for (ar = sc->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(NULL, ar);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index c82f3a3af23..5ef502e0182 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3092,7 +3092,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
- BKE_mask_free_nolib(mask_temp);
+ BKE_mask_free(mask_temp);
MEM_freeN(mask_temp);
BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
@@ -5154,7 +5154,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 518d8d68919..7094d5a3547 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -405,21 +405,28 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* use editmesh to avoid array allocation */
BMEditMesh *emtarget = NULL, *emaux = NULL;
- BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack;
- BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack;
+ union {
+ BVHTreeFromEditMesh emtreedata;
+ BVHTreeFromMesh dmtreedata;
+ } treedata_stack, auxdata_stack;
+
BVHTree *targ_tree;
void *targ_callback;
if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
emtarget = BKE_editmesh_from_object(calc->smd->target);
- if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) {
- targ_callback = emtreedata_stack.raycast_callback;
- treeData = &emtreedata_stack;
+ if ((targ_tree = bvhtree_from_editmesh_looptri(
+ &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache)))
+ {
+ targ_callback = treedata_stack.emtreedata.raycast_callback;
+ treeData = &treedata_stack.emtreedata;
}
}
else {
- if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) {
- targ_callback = dmtreedata_stack.raycast_callback;
- treeData = &dmtreedata_stack;
+ if ((targ_tree = bvhtree_from_mesh_looptri(
+ &treedata_stack.dmtreedata, calc->target, 0.0, 4, 6)))
+ {
+ targ_callback = treedata_stack.dmtreedata.raycast_callback;
+ treeData = &treedata_stack.dmtreedata;
}
}
if (targ_tree) {
@@ -429,15 +436,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
- if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) {
- aux_callback = emauxdata_stack.raycast_callback;
- auxData = &emauxdata_stack;
+ if ((aux_tree = bvhtree_from_editmesh_looptri(
+ &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache)))
+ {
+ aux_callback = auxdata_stack.emtreedata.raycast_callback;
+ auxData = &auxdata_stack.emtreedata;
}
}
else {
- if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) {
- aux_callback = dmauxdata_stack.raycast_callback;
- auxData = &dmauxdata_stack;
+ if ((aux_tree = bvhtree_from_mesh_looptri(&auxdata_stack.dmtreedata, auxMesh, 0.0, 4, 6)) != NULL) {
+ aux_callback = auxdata_stack.dmtreedata.raycast_callback;
+ auxData = &auxdata_stack.dmtreedata;
}
}
}
@@ -455,12 +464,21 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* free data structures */
if (treeData) {
- if (emtarget) free_bvhtree_from_editmesh(treeData);
- else free_bvhtree_from_mesh(treeData);
+ if (emtarget) {
+ free_bvhtree_from_editmesh(treeData);
+ }
+ else {
+ free_bvhtree_from_mesh(treeData);
+ }
}
+
if (auxData) {
- if (emaux) free_bvhtree_from_editmesh(auxData);
- else free_bvhtree_from_mesh(auxData);
+ if (emaux) {
+ free_bvhtree_from_editmesh(auxData);
+ }
+ else {
+ free_bvhtree_from_mesh(auxData);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 25a4fdc0cc7..8fec817d694 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/sound.c b/source/blender/blenkernel/intern/sound.c
index b016f8a49ed..414be73e234 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
}
+/** Free (or release) any data used by this sound (does not free the sound itself). */
void BKE_sound_free(bSound *sound)
{
+ /* No animdata here. */
+
if (sound->packedfile) {
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
@@ -148,8 +151,7 @@ void BKE_sound_free(bSound *sound)
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
- }
-
+ }
#endif /* WITH_AUDASPACE */
}
@@ -315,15 +317,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f
}
#endif
-void BKE_sound_delete(struct Main *bmain, bSound *sound)
-{
- if (sound) {
- BKE_sound_free(sound);
-
- BKE_libblock_free(bmain, sound);
- }
-}
-
void BKE_sound_cache(bSound *sound)
{
sound->flags |= SOUND_FLAGS_CACHING;
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index c452065fbad..e5075a2d382 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -141,8 +141,5 @@ void BKE_speaker_make_local(Speaker *spk)
void BKE_speaker_free(Speaker *spk)
{
- if (spk->sound)
- id_us_min(&spk->sound->id);
-
- BKE_animdata_free((ID *)spk);
+ BKE_animdata_free((ID *)spk, false);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 88bc3fb9854..b0d19320230 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2619,7 +2619,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false, fast);
- glShadeModel(GL_FLAT);
}
return;
@@ -3164,7 +3163,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
MEM_freeN(matconv);
}
- glShadeModel(GL_FLAT);
+ glShadeModel(GL_SMOOTH);
}
static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 6def9e3e503..fdc2edba57f 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text)
text->curl = text->sell = NULL;
}
+/** Free (or release) any data used by this text (does not free the text itself). */
void BKE_text_free(Text *text)
{
+ /* No animdata here. */
+
BKE_text_free_lines(text);
- if (text->name) MEM_freeN(text->name);
- MEM_freeN(text->undo_buf);
+ MEM_SAFE_FREE(text->name);
+ MEM_SAFE_FREE(text->undo_buf);
#ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
+ BPY_text_free_code(text);
#endif
}
@@ -495,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
return tan;
}
-void BKE_text_unlink(Main *bmain, Text *text)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Object *ob;
- bController *cont;
- bActuator *act;
- bConstraint *con;
- bNodeTree *ntree;
- bNode *node;
- Material *mat;
- Lamp *la;
- Tex *te;
- World *wo;
- FreestyleLineStyle *linestyle;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleModuleConfig *module;
- bool update;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- /* game controllers */
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- if (cont->type == CONT_PYTHON) {
- bPythonCont *pc;
-
- pc = cont->data;
- if (pc->text == text) pc->text = NULL;
- }
- }
- /* game actuators */
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *tfa;
-
- tfa = act->data;
- if (tfa->text == text) tfa->text = NULL;
- }
- }
-
- /* pyconstraints */
- update = 0;
-
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
-
- }
- }
- }
- }
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
- }
- }
-
- if (update)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* nodes */
- for (la = bmain->lamp.first; la; la = la->id.next) {
- ntree = la->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
- ntree = linestyle->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- ntree = mat->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (te = bmain->tex.first; te; te = te->id.next) {
- ntree = te->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- ntree = wo->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- ntree = sce->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- Text *ntext = (Text *)node->id;
- if (ntext == text) node->id = NULL;
- }
- }
-
- /* Freestyle (while looping over the scene) */
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
- if (module->script == text)
- module->script = NULL;
- }
- }
- }
-
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- /* text space */
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st = (SpaceText *) sl;
-
- if (st->text == text) {
- st->text = NULL;
- st->top = 0;
- }
- }
- }
- }
- }
-
- text->id.us = 0;
-}
-
void BKE_text_clear(Text *text) /* called directly from rna */
{
int oldstate;
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index d353042b711..9326ece7a4b 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -557,23 +557,38 @@ int colorband_element_remove(struct ColorBand *coba, int index)
/* ******************* TEX ************************ */
+/** Free (or release) any data used by this texture (does not free the texure itself). */
void BKE_texture_free(Tex *tex)
{
- if (tex->coba) MEM_freeN(tex->coba);
- if (tex->env) BKE_texture_envmap_free(tex->env);
- if (tex->pd) BKE_texture_pointdensity_free(tex->pd);
- if (tex->vd) BKE_texture_voxeldata_free(tex->vd);
- if (tex->ot) BKE_texture_ocean_free(tex->ot);
- BKE_animdata_free((struct ID *)tex);
-
- BKE_previewimg_free(&tex->preview);
- BKE_icon_id_delete((struct ID *)tex);
- tex->id.icon_id = 0;
-
+ BKE_animdata_free((ID *)tex, false);
+
+ /* is no lib link block, but texture extension */
if (tex->nodetree) {
ntreeFreeTree(tex->nodetree);
MEM_freeN(tex->nodetree);
+ tex->nodetree = NULL;
}
+
+ MEM_SAFE_FREE(tex->coba);
+ if (tex->env) {
+ BKE_texture_envmap_free(tex->env);
+ tex->env = NULL;
+ }
+ if (tex->pd) {
+ BKE_texture_pointdensity_free(tex->pd);
+ tex->pd = NULL;
+ }
+ if (tex->vd) {
+ BKE_texture_voxeldata_free(tex->vd);
+ tex->vd = NULL;
+ }
+ if (tex->ot) {
+ BKE_texture_ocean_free(tex->ot);
+ tex->ot = NULL;
+ }
+
+ BKE_icon_id_delete((ID *)tex);
+ BKE_previewimg_free(&tex->preview);
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 3c2444b0ef1..a40e4f72636 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -529,7 +529,7 @@ typedef struct AccessCacheKey {
static unsigned int accesscache_hashhash(const void *key_v)
{
const AccessCacheKey *key = (const AccessCacheKey *) key_v;
- /* TODP(sergey): Need better hasing here for faster frame access. */
+ /* TODP(sergey): Need better hashing here for faster frame access. */
return key->clip_index << 16 | key->frame;
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 66fe0491373..1217992741a 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -53,41 +53,30 @@
#include "GPU_material.h"
#include "GPU_probe.h"
-void BKE_world_free_ex(World *wrld, bool do_id_user)
+/** Free (or release) any data used by this world (does not free the world itself). */
+void BKE_world_free(World *wrld)
{
- MTex *mtex;
int a;
-
+
+ BKE_animdata_free((ID *)wrld, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(wrld->mtex[a]);
}
- BKE_previewimg_free(&wrld->preview);
-
- BKE_animdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeTree_ex(wrld->nodetree, do_id_user);
+ ntreeFreeTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
+ wrld->nodetree = NULL;
}
- if (wrld->gpumaterial.first)
- GPU_material_free(&wrld->gpumaterial);
+ GPU_material_free(&wrld->gpumaterial);
- if (wrld->gpuprobe.first)
- GPU_probe_free(&wrld->gpuprobe);
+ GPU_probe_free(&wrld->gpuprobe);
BKE_icon_id_delete((struct ID *)wrld);
- wrld->id.icon_id = 0;
-}
-
-void BKE_world_free(World *wrld)
-{
- BKE_world_free_ex(wrld, true);
+ BKE_previewimg_free(&wrld->preview);
}
void BKE_world_init(World *wrld)
diff --git a/source/blender/blenlib/BLI_array_store_utils.h b/source/blender/blenlib/BLI_array_store_utils.h
new file mode 100644
index 00000000000..6b2a28846f4
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_store_utils.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ARRAY_STORE_UTILS_H__
+#define __BLI_ARRAY_STORE_UTILS_H__
+
+/** \file BLI_array_store_utils.h
+ * \ingroup bli
+ */
+
+struct BArrayStore;
+
+struct BArrayStore_AtSize {
+ struct BArrayStore **stride_table;
+ int stride_table_len;
+};
+
+BArrayStore *BLI_array_store_at_size_ensure(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride, const int chunk_size);
+
+BArrayStore *BLI_array_store_at_size_get(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride);
+
+void BLI_array_store_at_size_clear(
+ struct BArrayStore_AtSize *bs_stride);
+
+void BLI_array_store_at_size_calc_memory_usage(
+ struct BArrayStore_AtSize *bs_stride,
+ size_t *r_size_expanded, size_t *r_size_compacted);
+
+#endif /* __BLI_ARRAY_STORE_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 5ef8421c003..a46c87cec40 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+#define BLI_array_rfindindex(arr, arr_len, p) \
+ _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
+
void _bli_array_binary_and(
void *arr, const void *arr_a, const void *arr_b,
unsigned int arr_len, size_t arr_stride);
diff --git a/source/blender/blenlib/BLI_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_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 6d6fbe4e7af..8124e07dd47 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -138,10 +138,14 @@ bool invert_m3_m3(float R[3][3], float A[3][3]);
bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], float A[4][4]);
-/* double ariphmetics */
+/* double arithmetic (mixed float/double) */
void mul_m4_v4d(float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]);
+/* double matrix functions (no mixing types) */
+void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]);
+void mul_m3_v3_db(double M[3][3], double r[3]);
+
/****************************** Linear Algebra *******************************/
@@ -269,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
/*********************************** Other ***********************************/
void print_m3(const char *str, float M[3][3]);
-void print_m4(const char *str, float M[3][4]);
+void print_m4(const char *str, float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 5f76b79b298..8a36b047bad 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -148,6 +148,7 @@ MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[3]);
MINLINE void negate_v3_short(short r[3]);
+MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
@@ -231,6 +232,7 @@ void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
+
/********************************* Comparison ********************************/
MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -282,18 +284,18 @@ void angle_poly_v3(float *angles, const float *verts[3], int len);
/********************************* Geometry **********************************/
-void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]);
-void project_v3_v3v3(float r[3], const float p[3], const float n[3]);
-void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]);
-void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]);
-void project_v3_plane(float v[3], const float n[3], const float p[3]);
-void reflect_v3_v3v3(float r[3], const float v[3], const float n[3]);
+void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
+void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
+void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
+void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
+void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
-void ortho_v3_v3(float p[3], const float v[3]);
-void ortho_v2_v2(float p[2], const float v[2]);
+void ortho_v3_v3(float out[3], const float v[3]);
+void ortho_v2_v2(float out[2], const float v[2]);
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
-void rotate_normalized_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle);
/*********************************** Other ***********************************/
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index eaf9c7a0738..d46a221d108 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -39,8 +39,7 @@ typedef struct Quadric {
/* conversion */
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
-void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]);
-void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]);
+void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
@@ -50,7 +49,7 @@ void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
void BLI_quadric_mul(Quadric *a, const double scalar);
/* solve */
-double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]);
-bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon);
+double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
+bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
#endif /* __BLI_QUADRIC_H__ */
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index 7b84dddcb68..f36d2faa1b8 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -49,6 +49,7 @@ void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 42d958774d8..9978d1d19af 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
intern/BLI_mempool.c
intern/DLRB_tree.c
intern/array_store.c
+ intern/array_store_utils.c
intern/array_utils.c
intern/astar.c
intern/boxpack2d.c
@@ -122,6 +123,7 @@ set(SRC
BLI_args.h
BLI_array.h
BLI_array_store.h
+ BLI_array_store_utils.h
BLI_array_utils.h
BLI_astar.h
BLI_bitmap.h
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 527d9934797..76de52bda66 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string(
/**
* Deep-duplicate of a single direntry.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
@@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
/**
* Deep-duplicate of an array of direntries, including the array itself.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_duplicate(
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries)
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 06946e520a8..f943a8119c4 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -69,7 +69,7 @@ const unsigned int hashsizes[] = {
/**
* \note Max load #GHASH_LIMIT_GROW used to be 3. (pre 2.74).
- * Python uses 0.6666, tommyhaslib even goes down to 0.5.
+ * Python uses 0.6666, tommyhashlib even goes down to 0.5.
* Reducing our from 3 to 0.75 gives huge speedup (about twice quicker pure GHash insertions/lookup,
* about 25% - 30% quicker 'dynamic-topology' stroke drawing e.g.).
* Min load #GHASH_LIMIT_SHRINK is a quarter of max load, to avoid resizing to quickly.
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/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index b7a51f2c48e..783dba5510c 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -622,7 +622,7 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
iter->curindex = 0;
iter->curchunk = iter->curchunk->next;
if (iter->curchunk == NULL) {
- return NULL;
+ return (ret->freeword == FREEWORD) ? NULL : ret;
}
curnode = CHUNK_DATA(iter->curchunk);
}
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index 9baccf38fa3..33565596c1f 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -36,7 +36,7 @@
*
* This diagram is an overview of the structure of a single array-store.
*
- * \note The only 2 structues here which are referenced externally are the.
+ * \note The only 2 structures here which are referenced externally are the.
*
* - BArrayStore: The whole array store.
* - BArrayState: Represents a single state (array) of data.
@@ -92,7 +92,7 @@
* First matches at either end of the array are detected.
* For identical arrays this is all thats needed.
*
- * De-duplication is performed on any remaining chunks, by hasing the first few bytes of the chunk
+ * De-duplication is performed on any remaining chunks, by hashing the first few bytes of the chunk
* (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS).
*
* \note This is cached for reuse since the referenced data never changes.
@@ -650,7 +650,7 @@ static void bchunk_list_append_data(
* Use for adding arrays of arbitrary sized memory at once.
*
* \note This function takes care not to perform redundant chunk-merging checks,
- * so we can write succesive fixed size chunks quickly.
+ * so we can write successive fixed size chunks quickly.
*/
static void bchunk_list_append_data_n(
const BArrayInfo *info, BArrayMemory *bs_mem,
@@ -1680,7 +1680,7 @@ void *BLI_array_store_state_data_get_alloc(
/** \} */
-/** \name Debigging API (for testing).
+/** \name Debugging API (for testing).
* \{ */
/* only for test validation */
diff --git a/source/blender/blenlib/intern/array_store_utils.c b/source/blender/blenlib/intern/array_store_utils.c
new file mode 100644
index 00000000000..83cd28ddf11
--- /dev/null
+++ b/source/blender/blenlib/intern/array_store_utils.c
@@ -0,0 +1,103 @@
+/*
+ * ***** 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/blenlib/intern/array_store_utils.c
+ * \ingroup bli
+ * \brief Helper functions for BLI_array_store API.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_array_store.h"
+#include "BLI_array_store_utils.h" /* own include */
+
+#include "BLI_math_base.h"
+
+BArrayStore *BLI_array_store_at_size_ensure(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride, const int chunk_size)
+{
+ if (bs_stride->stride_table_len < stride) {
+ bs_stride->stride_table_len = stride;
+ bs_stride->stride_table = MEM_recallocN(bs_stride->stride_table, sizeof(*bs_stride->stride_table) * stride);
+ }
+ BArrayStore **bs_p = &bs_stride->stride_table[stride - 1];
+
+ if ((*bs_p) == NULL) {
+#if 0
+ unsigned int chunk_count = chunk_size;
+#else
+ /* calculate best chunk-count to fit a power of two */
+ unsigned int chunk_count = chunk_size;
+ {
+ unsigned int size = chunk_count * stride;
+ size = power_of_2_max_u(size);
+ size = MEM_SIZE_OPTIMAL(size);
+ chunk_count = size / stride;
+ }
+#endif
+
+ (*bs_p) = BLI_array_store_create(stride, chunk_count);
+ }
+ return *bs_p;
+}
+
+BArrayStore *BLI_array_store_at_size_get(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride)
+{
+ BLI_assert(stride > 0 && stride <= bs_stride->stride_table_len);
+ return bs_stride->stride_table[stride - 1];
+}
+
+void BLI_array_store_at_size_clear(
+ struct BArrayStore_AtSize *bs_stride)
+{
+ for (int i = 0; i < bs_stride->stride_table_len; i += 1) {
+ if (bs_stride->stride_table[i]) {
+ BLI_array_store_destroy(bs_stride->stride_table[i]);
+ }
+ }
+
+ MEM_freeN(bs_stride->stride_table);
+ bs_stride->stride_table = NULL;
+ bs_stride->stride_table_len = 0;
+}
+
+
+void BLI_array_store_at_size_calc_memory_usage(
+ struct BArrayStore_AtSize *bs_stride,
+ size_t *r_size_expanded, size_t *r_size_compacted)
+{
+ size_t size_compacted = 0;
+ size_t size_expanded = 0;
+ for (int i = 0; i < bs_stride->stride_table_len; i++) {
+ BArrayStore *bs = bs_stride->stride_table[i];
+ if (bs) {
+ size_compacted += BLI_array_store_calc_size_compacted_get(bs);
+ size_expanded += BLI_array_store_calc_size_expanded_get(bs);
+ }
+ }
+
+ *r_size_expanded = size_expanded;
+ *r_size_compacted = size_compacted;
+}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 5d485e2033d..32f0111babd 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -134,8 +134,22 @@ void _bli_array_permute(
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
- unsigned int i;
- for (i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ if (memcmp(arr_step, p, arr_stride) == 0) {
+ return (int)i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+{
+ const char *arr_step = (const char *)arr + (arr_stride * arr_len);
+ for (unsigned int i = arr_len; i-- != 0; ) {
+ arr_step -= arr_stride;
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
}
@@ -183,7 +197,7 @@ void _bli_array_binary_or(
* \param user_data: User data for \a test_fn.
* \param span_step: Indices to iterate over,
* initialize both values to the array length to initialize iteration.
- * \param: r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
* where calculating the length isnt a simple subtraction.
*/
bool _bli_array_iter_span(
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index d98b915983c..c73fe7a3ff1 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -112,7 +112,7 @@ static void md5_init_ctx(struct md5_ctx *ctx)
* the 'ctx' context for the next 'len' bytes starting at 'buffer'.
* It is necessary that 'len' is a multiple of 64!!!
*/
-static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
{
/* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321.
* The first function is a little bit optimized (as found in Colin Plumbs public domain implementation).
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 180d62105c4..abb8ff35a45 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -65,7 +65,7 @@ MALWAYS_INLINE __m128 linearrgb_to_srgb_v4_simd(const __m128 c)
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
{
- float r[4] = {srgb[0], srgb[1], srgb[2], 0.0f};
+ float r[4] = {srgb[0], srgb[1], srgb[2], 1.0f};
__m128 *rv = (__m128 *)&r;
*rv = srgb_to_linearrgb_v4_simd(*rv);
linear[0] = r[0];
@@ -75,7 +75,7 @@ MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
{
- float r[4] = {linear[0], linear[1], linear[2], 0.0f};
+ float r[4] = {linear[0], linear[1], linear[2], 1.0f};
__m128 *rv = (__m128 *)&r;
*rv = linearrgb_to_srgb_v4_simd(*rv);
srgb[0] = r[0];
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 370e8bb0035..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.
*
@@ -2692,7 +2753,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v
}
/**
- * \param r_vi The point \a p projected onto the triangle.
+ * \param r_isect_co: The point \a p projected onto the triangle.
* \return True when \a p is inside the triangle.
* \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
*/
@@ -5002,7 +5063,9 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
BLI_ASSERT_UNIT_V3(tan_l);
BLI_ASSERT_UNIT_V3(tan_r);
- const float eps = 1e-7f;
+ /* -7f causes instability/glitches with Bendy Bones + Custom Refs */
+ const float eps = 1e-5f;
+
const float tan_dot = dot_v3v3(tan_l, tan_r);
if (tan_dot > 1.0f - eps) {
/* no angle difference (use fallback, length wont make any difference) */
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 0e3f905ef16..c9c61d5c878 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -587,6 +587,15 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3])
r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
+void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3])
+{
+ BLI_assert(r != a);
+
+ r[0] = M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
+ r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
+ r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
+}
+
void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
{
BLI_assert(r != a);
@@ -597,10 +606,12 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
void mul_m3_v3(float M[3][3], float r[3])
{
- float tmp[3];
+ mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)});
+}
- mul_v3_m3v3(tmp, M, r);
- copy_v3_v3(r, tmp);
+void mul_m3_v3_db(double M[3][3], double r[3])
+{
+ mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)});
}
void mul_transposed_m3_v3(float mat[3][3], float vec[3])
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 7f2db3743df..988034349e0 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -585,23 +585,27 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/********************************* Geometry **********************************/
-/* Project v1 on v2 */
-void project_v2_v2v2(float c[2], const float v1[2], const float v2[2])
+/**
+ * Project \a p onto \a v_proj
+ */
+void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
- const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2);
+ const float mul = dot_v2v2(p, v_proj) / dot_v2v2(v_proj, v_proj);
- c[0] = mul * v2[0];
- c[1] = mul * v2[1];
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
}
-/* Project v1 on v2 */
-void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
+/**
+ * Project \a p onto \a v_proj
+ */
+void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
- const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2);
+ const float mul = dot_v3v3(p, v_proj) / dot_v3v3(v_proj, v_proj);
- c[0] = mul * v2[0];
- c[1] = mul * v2[1];
- c[2] = mul * v2[2];
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
+ out[2] = mul * v_proj[2];
}
/**
@@ -617,35 +621,35 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
* sub_v3_v3v3(c, v, c);
* \endcode
*/
-void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3])
+void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
- const float mul = dot_v3v3(v, v_plane) / dot_v3v3(v_plane, v_plane);
+ const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
- c[0] = v[0] - (mul * v_plane[0]);
- c[1] = v[1] - (mul * v_plane[1]);
- c[2] = v[2] - (mul * v_plane[2]);
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
+ out[2] = p[2] - (mul * v_plane[2]);
}
-void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2])
+void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
{
- const float mul = dot_v2v2(v, v_plane) / dot_v2v2(v_plane, v_plane);
+ const float mul = dot_v2v2(p, v_plane) / dot_v2v2(v_plane, v_plane);
- c[0] = v[0] - (mul * v_plane[0]);
- c[1] = v[1] - (mul * v_plane[1]);
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
}
/* project a vector on a plane defined by normal and a plane point p */
-void project_v3_plane(float v[3], const float n[3], const float p[3])
+void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
float vector[3];
float mul;
- sub_v3_v3v3(vector, v, p);
- mul = dot_v3v3(vector, n) / len_squared_v3(n);
+ sub_v3_v3v3(vector, out, plane_co);
+ mul = dot_v3v3(vector, plane_no) / len_squared_v3(plane_no);
- mul_v3_v3fl(vector, n, mul);
+ mul_v3_v3fl(vector, plane_no, mul);
- sub_v3_v3(v, vector);
+ sub_v3_v3(out, vector);
}
/* Returns a vector bisecting the angle at v2 formed by v1, v2 and v3 */
@@ -664,15 +668,15 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const
* Returns a reflection vector from a vector and a normal vector
* reflect = vec - ((2 * DotVecs(vec, mirror)) * mirror)
*/
-void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3])
+void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
- const float dot2 = 2.0f * dot_v3v3(vec, normal);
+ const float dot2 = 2.0f * dot_v3v3(v, normal);
BLI_ASSERT_UNIT_V3(normal);
- out[0] = vec[0] - (dot2 * normal[0]);
- out[1] = vec[1] - (dot2 * normal[1]);
- out[2] = vec[2] - (dot2 * normal[2]);
+ out[0] = v[0] - (dot2 * normal[0]);
+ out[1] = v[1] - (dot2 * normal[1]);
+ out[2] = v[2] - (dot2 * normal[2]);
}
/**
@@ -710,27 +714,27 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
*
* \note return vector won't maintain same length.
*/
-void ortho_v3_v3(float p[3], const float v[3])
+void ortho_v3_v3(float out[3], const float v[3])
{
const int axis = axis_dominant_v3_single(v);
- BLI_assert(p != v);
+ BLI_assert(out != v);
switch (axis) {
case 0:
- p[0] = -v[1] - v[2];
- p[1] = v[0];
- p[2] = v[0];
+ out[0] = -v[1] - v[2];
+ out[1] = v[0];
+ out[2] = v[0];
break;
case 1:
- p[0] = v[1];
- p[1] = -v[0] - v[2];
- p[2] = v[1];
+ out[0] = v[1];
+ out[1] = -v[0] - v[2];
+ out[2] = v[1];
break;
case 2:
- p[0] = v[2];
- p[1] = v[2];
- p[2] = -v[0] - v[1];
+ out[0] = v[2];
+ out[1] = v[2];
+ out[2] = -v[0] - v[1];
break;
}
}
@@ -738,18 +742,19 @@ void ortho_v3_v3(float p[3], const float v[3])
/**
* no brainer compared to v3, just have for consistency.
*/
-void ortho_v2_v2(float p[2], const float v[2])
+void ortho_v2_v2(float out[2], const float v[2])
{
- BLI_assert(p != v);
+ BLI_assert(out != v);
- p[0] = -v[1];
- p[1] = v[0];
+ out[0] = -v[1];
+ out[1] = v[0];
}
-/* Rotate a point p by angle theta around an arbitrary axis r
+/**
+ * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
* http://local.wasp.uwa.edu.au/~pbourke/geometry/
*/
-void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle)
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle)
{
const float costheta = cosf(angle);
const float sintheta = sinf(angle);
@@ -757,17 +762,17 @@ void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[
/* double check they are normalized */
BLI_ASSERT_UNIT_V3(axis);
- r[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) +
- (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) +
- (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]);
+ out[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) +
+ (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) +
+ (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]);
- r[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) +
- ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) +
- (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]);
+ out[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) +
+ ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) +
+ (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]);
- r[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) +
- (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) +
- ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]);
+ out[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) +
+ (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) +
+ ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]);
}
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle)
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index b43fb6e986c..fd9f3d5ff99 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -633,6 +633,13 @@ MINLINE void negate_v3_short(short r[3])
r[2] = (short)-r[2];
}
+MINLINE void negate_v3_db(double r[3])
+{
+ r[0] = -r[0];
+ r[1] = -r[1];
+ r[2] = -r[2];
+}
+
MINLINE void invert_v2(float r[2])
{
BLI_assert(!ELEM(0.0f, r[0], r[1]));
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 2b793841c38..ded10ad7713 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
/**
* Remove redundant characters from \a path and optionally make absolute.
*
- * \param relbase: The path this is relative to, or ignored when NULL.
+ * \param relabase: The path this is relative to, or ignored when NULL.
* \param path: Can be any input, and this function converts it to a regular full path.
* Also removes garbage from directory paths, like `/../` or double slashes etc.
*
diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c
index 588cd9c2cb5..c9d27494455 100644
--- a/source/blender/blenlib/intern/quadric.c
+++ b/source/blender/blenlib/intern/quadric.c
@@ -63,26 +63,68 @@ void BLI_quadric_from_plane(Quadric *q, const double v[4])
q->d2 = v[3] * v[3];
}
-void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3])
+#if 0 /* UNUSED */
+
+static void quadric_to_tensor_m3(const Quadric *q, double m[3][3])
{
- m[0][0] = (float)q->a2;
- m[0][1] = (float)q->ab;
- m[0][2] = (float)q->ac;
+ m[0][0] = q->a2;
+ m[0][1] = q->ab;
+ m[0][2] = q->ac;
- m[1][0] = (float)q->ab;
- m[1][1] = (float)q->b2;
- m[1][2] = (float)q->bc;
+ m[1][0] = q->ab;
+ m[1][1] = q->b2;
+ m[1][2] = q->bc;
- m[2][0] = (float)q->ac;
- m[2][1] = (float)q->bc;
- m[2][2] = (float)q->c2;
+ m[2][0] = q->ac;
+ m[2][1] = q->bc;
+ m[2][2] = q->c2;
}
-void BLI_quadric_to_vector_v3(const Quadric *q, float v[3])
+#endif
+
+/**
+ * Inline inverse matrix creation.
+ * Equivalent of:
+ *
+ * \code{.c}
+ * quadric_to_tensor_m3(q, m);
+ * invert_m3_db(m, eps);
+ * \endcode
+ */
+static bool quadric_to_tensor_m3_inverse(const Quadric *q, double m[3][3], double epsilon)
{
- v[0] = (float)q->ad;
- v[1] = (float)q->bd;
- v[2] = (float)q->cd;
+ const double det =
+ (q->a2 * (q->b2 * q->c2 - q->bc * q->bc) -
+ q->ab * (q->ab * q->c2 - q->ac * q->bc) +
+ q->ac * (q->ab * q->bc - q->ac * q->b2));
+
+ if (fabs(det) > epsilon) {
+ const double invdet = 1.0 / det;
+
+ m[0][0] = (q->b2 * q->c2 - q->bc * q->bc) * invdet;
+ m[1][0] = (q->bc * q->ac - q->ab * q->c2) * invdet;
+ m[2][0] = (q->ab * q->bc - q->b2 * q->ac) * invdet;
+
+ m[0][1] = (q->ac * q->bc - q->ab * q->c2) * invdet;
+ m[1][1] = (q->a2 * q->c2 - q->ac * q->ac) * invdet;
+ m[2][1] = (q->ab * q->ac - q->a2 * q->bc) * invdet;
+
+ m[0][2] = (q->ab * q->bc - q->ac * q->b2) * invdet;
+ m[1][2] = (q->ac * q->ab - q->a2 * q->bc) * invdet;
+ m[2][2] = (q->a2 * q->b2 - q->ab * q->ab) * invdet;
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void BLI_quadric_to_vector_v3(const Quadric *q, double v[3])
+{
+ v[0] = q->ad;
+ v[1] = q->bd;
+ v[2] = q->cd;
}
void BLI_quadric_clear(Quadric *q)
@@ -105,26 +147,22 @@ void BLI_quadric_mul(Quadric *a, const double scalar)
mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar);
}
-double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3])
+double BLI_quadric_evaluate(const Quadric *q, const double v[3])
{
- const double v[3] = {UNPACK3(v_fl)};
return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) +
(q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) +
(q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) +
(q->d2));
}
-bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon)
+bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon)
{
- float m[3][3];
+ double m[3][3];
- BLI_quadric_to_tensor_m3(q, m);
-
- if (invert_m3_ex(m, epsilon)) {
+ if (quadric_to_tensor_m3_inverse(q, m, epsilon)) {
BLI_quadric_to_vector_v3(q, v);
- mul_m3_v3(m, v);
- negate_v3(v);
-
+ mul_m3_v3_db(m, v);
+ negate_v3_db(v);
return true;
}
else {
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 66c568a7ff3..40d9a3da3d9 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -46,6 +46,7 @@
#define MULTIPLIER 0x5DEECE66Dll
#define MASK 0x0000FFFFFFFFFFFFll
+#define MASK_BYTES 2
#define ADDEND 0xB
#define LOWSEED 0x330E
@@ -107,6 +108,45 @@ BLI_INLINE void rng_step(RNG *rng)
rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
}
+void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len)
+{
+ size_t last_len = 0;
+ size_t trim_len = bytes_len;
+
+#define RAND_STRIDE (sizeof(rng->X) - MASK_BYTES)
+
+ if (trim_len > RAND_STRIDE) {
+ last_len = trim_len % RAND_STRIDE;
+ trim_len = trim_len - last_len;
+ }
+ else {
+ trim_len = 0;
+ last_len = bytes_len;
+ }
+
+ const char *data_src = (void *)&(rng->X);
+ size_t i = 0;
+ while (i != trim_len) {
+ BLI_assert(i < trim_len);
+#ifdef __BIG_ENDIAN__
+ for (size_t j = (RAND_STRIDE + MASK_BYTES) - 1; j != MASK_BYTES - 1; j--)
+#else
+ for (size_t j = 0; j != RAND_STRIDE; j++)
+#endif
+ {
+ bytes[i++] = data_src[j];
+ }
+ rng_step(rng);
+ }
+ if (last_len) {
+ for (size_t j = 0; j != last_len; j++) {
+ bytes[i++] = data_src[j];
+ }
+ }
+
+#undef RAND_STRIDE
+}
+
int BLI_rng_get_int(RNG *rng)
{
rng_step(rng);
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index aba7c9d5ee2..3edc00a8c1a 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -389,7 +389,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
/*
* size = because on win32 reading
* all the bytes in the file will return
- * less bytes because of crnl changes.
+ * less bytes because of `CRNL` changes.
*/
size = fread(buf, 1, size, fp);
for (i = 0; i <= size; i++) {
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 58475b7f835..bd7b7f9cdbd 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -928,7 +928,7 @@ static void task_parallel_range_ex(
func_finalize(userdata, userdata_chunk_local);
}
}
- MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
}
}
@@ -992,7 +992,8 @@ void BLI_task_parallel_range(
* (similar to OpenMP's firstprivate).
* \param userdata_chunk_size Memory size of \a userdata_chunk.
* \param func_ex Callback function (advanced version).
- * \param func_finalize Callback function, called after all workers have finisehd, useful to finalize accumulative tasks.
+ * \param func_finalize Callback function, called after all workers have finished,
+ * useful to finalize accumulative tasks.
* \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
* (allows caller to use any kind of test to switch on parallelization or not).
* \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index bf47682297d..c85cf128643 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -100,7 +100,8 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con
struct ID *BLO_library_link_named_part_ex(
struct Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const short flag,
- struct Scene *scene, struct View3D *v3d);
+ struct Scene *scene, struct View3D *v3d,
+ const bool use_placeholders, const bool force_indirect);
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 8364df38208..479d3a15e6c 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -35,6 +35,10 @@ set(INC
../nodes
../render/extern/include
../../../intern/guardedalloc
+
+ # for writefile.c: dna_type_offsets.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
+
)
set(INC_SYS
@@ -74,3 +78,6 @@ if(WITH_CODEC_FFMPEG)
endif()
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
+
+# needed so writefile.c can use dna_type_offsets.h
+add_dependencies(bf_blenloader bf_dna)
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 3cae95d418e..be893177b3b 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -411,22 +411,23 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
/* Even though directly used libs have been already moved to new main, indirect ones have not.
* This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
* data may remain in memory, but think we'll have to live with it. */
- Main *libmain;
+ Main *libmain, *libmain_next;
Main *newmain = bfd->main;
ListBase new_mainlist = {newmain, newmain};
- for (libmain = oldmain->next; libmain; libmain = libmain->next) {
+ for (libmain = oldmain->next; libmain; libmain = libmain_next) {
+ libmain_next = libmain->next;
/* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent
* to detect indirect-linked ones... */
if (libmain->curlib && (libmain->curlib->parent != NULL)) {
BLI_remlink(&old_mainlist, libmain);
BLI_addtail(&new_mainlist, libmain);
}
-#if 0
else {
+#ifdef PRINT_DEBUG
printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
- }
#endif
+ }
}
/* In any case, we need to move all lib datablocks themselves - those are 'first level data',
* getting rid of them would imply updating spaces & co to prevent invalid pointers access. */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 10f603c9f6b..67597661470 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -113,6 +113,7 @@
#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"
@@ -124,6 +125,7 @@
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
+#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_material.h"
@@ -159,69 +161,74 @@
#include <errno.h>
-/*
- * Remark: still a weak point is the newaddress() function, that doesnt solve reading from
- * multiple files at the same time
- *
- * (added remark: oh, i thought that was solved? will look at that... (ton)
- *
+/**
* READ
- * - Existing Library (Main) push or free
- * - allocate new Main
+ * ====
+ *
+ * - Existing Library (#Main) push or free
+ * - allocate new #Main
* - load file
- * - read SDNA
+ * - read #SDNA
* - for each LibBlock
- * - read LibBlock
- * - if a Library
- * - make a new Main
- * - attach ID's to it
- * - else
- * - read associated 'direct data'
- * - link direct data (internal and to LibBlock)
- * - read FileGlobal
- * - read USER data, only when indicated (file is ~/X.XX/startup.blend)
+ * - read LibBlock
+ * - if a Library
+ * - make a new #Main
+ * - attach ID's to it
+ * - else
+ * - read associated 'direct data'
+ * - link direct data (internal and to LibBlock)
+ * - read #FileGlobal
+ * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``)
* - free file
- * - per Library (per Main)
- * - read file
- * - read SDNA
- * - find LibBlocks and attach IDs to Main
- * - if external LibBlock
- * - search all Main's
- * - or it's already read,
- * - or not read yet
- * - or make new Main
- * - per LibBlock
- * - read recursive
- * - read associated direct data
- * - link direct data (internal and to LibBlock)
- * - free file
+ * - per Library (per #Main)
+ * - read file
+ * - read #SDNA
+ * - find LibBlocks and attach #ID's to #Main
+ * - if external LibBlock
+ * - search all #Main's
+ * - or it's already read,
+ * - or not read yet
+ * - or make new #Main
+ * - per LibBlock
+ * - read recursive
+ * - read associated direct data
+ * - link direct data (internal and to LibBlock)
+ * - free file
* - per Library with unread LibBlocks
- * - read file
- * - read SDNA
- * - per LibBlock
- * - read recursive
- * - read associated direct data
- * - link direct data (internal and to LibBlock)
- * - free file
- * - join all Mains
+ * - read file
+ * - read #SDNA
+ * - per LibBlock
+ * - read recursive
+ * - read associated direct data
+ * - link direct data (internal and to LibBlock)
+ * - free file
+ * - join all #Main's
* - link all LibBlocks and indirect pointers to libblocks
- * - initialize FileGlobal and copy pointers to Global
+ * - initialize #FileGlobal and copy pointers to #Global
+ *
+ * \note Still a weak point is the new-address function, that doesnt solve reading from
+ * multiple files at the same time.
+ * (added remark: oh, i thought that was solved? will look at that... (ton).
*/
/* use GHash for BHead name-based lookups (speeds up linking) */
#define USE_GHASH_BHEAD
+/* Use GHash for restoring pointers by name */
+#define USE_GHASH_RESTORE_POINTER
+
/***/
typedef struct OldNew {
- void *old, *newp;
+ const void *old;
+ void *newp;
int nr;
} OldNew;
typedef struct OldNewMap {
OldNew *entries;
int nentries, entriessize;
- int sorted;
+ bool sorted;
int lasthit;
} OldNewMap;
@@ -287,12 +294,13 @@ static int verg_oldnewmap(const void *v1, const void *v2)
static void oldnewmap_sort(FileData *fd)
{
+ BLI_assert(fd->libmap->sorted == false);
qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
fd->libmap->sorted = 1;
}
/* nr is zero for data, and ID code for libdata */
-static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
OldNew *entry;
@@ -309,7 +317,7 @@ static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int n
entry->nr = nr;
}
-void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
@@ -364,7 +372,7 @@ static int oldnewmap_lookup_entry_full(const OldNewMap *onm, const void *addr, i
return -1;
}
-static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
{
int i;
@@ -394,7 +402,7 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_
}
/* for libdata, nr has ID code, no increment */
-static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
{
if (addr == NULL) {
return NULL;
@@ -402,11 +410,8 @@ static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
/* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
if (onm->sorted) {
- OldNew entry_s, *entry;
-
- entry_s.old = addr;
-
- entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ const OldNew entry_s = {.old = addr};
+ OldNew *entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
if (entry) {
ID *id = entry->newp;
@@ -486,53 +491,57 @@ void blo_join_main(ListBase *mainlist)
}
}
-static void split_libdata(ListBase *lb, Main *first)
+static void split_libdata(ListBase *lb_src, Main **lib_main_array, const unsigned int lib_main_array_len)
{
- ListBase *lbn;
- ID *id, *idnext;
- Main *mainvar;
-
- id = lb->first;
- while (id) {
+ for (ID *id = lb_src->first, *idnext; id; id = idnext) {
idnext = id->next;
+
if (id->lib) {
- mainvar = first;
- while (mainvar) {
- if (mainvar->curlib == id->lib) {
- lbn= which_libbase(mainvar, GS(id->name));
- BLI_remlink(lb, id);
- BLI_addtail(lbn, id);
- break;
- }
- mainvar = mainvar->next;
+ if (((unsigned int)id->lib->temp_index < lib_main_array_len) &&
+ /* this check should never fail, just incase 'id->lib' is a dangling pointer. */
+ (lib_main_array[id->lib->temp_index]->curlib == id->lib))
+ {
+ Main *mainvar = lib_main_array[id->lib->temp_index];
+ ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ else {
+ printf("%s: invalid library for '%s'\n", __func__, id->name);
+ BLI_assert(0);
}
- if (mainvar == NULL) printf("error split_libdata\n");
}
- id = idnext;
}
}
void blo_split_main(ListBase *mainlist, Main *main)
{
- ListBase *lbarray[MAX_LIBARRAY];
- Library *lib;
- int i;
-
mainlist->first = mainlist->last = main;
main->next = NULL;
if (BLI_listbase_is_empty(&main->library))
return;
- for (lib = main->library.first; lib; lib = lib->id.next) {
+ /* (Library.temp_index -> Main), lookup table */
+ const unsigned int lib_main_array_len = BLI_listbase_count(&main->library);
+ Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__);
+
+ int i = 0;
+ for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
BLI_addtail(mainlist, libmain);
+ lib->temp_index = i;
+ lib_main_array[i] = libmain;
}
+ ListBase *lbarray[MAX_LIBARRAY];
i = set_listbasepointers(main, lbarray);
- while (i--)
- split_libdata(lbarray[i], main->next);
+ while (i--) {
+ split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
+ }
+
+ MEM_freeN(lib_main_array);
}
static void read_file_version(FileData *fd, Main *main)
@@ -871,8 +880,6 @@ static void decode_blender_header(FileData *fd)
if (readsize == sizeof(header)) {
if (STREQLEN(header, "BLENDER", 7)) {
- int remove_this_endian_test = 1;
-
fd->flags |= FD_FLAGS_FILE_OK;
/* what size are pointers in the file ? */
@@ -891,7 +898,7 @@ static void decode_blender_header(FileData *fd)
/* is the file saved in a different endian
* than we need ?
*/
- if (((((char *)&remove_this_endian_test)[0] == 1) ? L_ENDIAN : B_ENDIAN) != ((header[8] == 'v') ? L_ENDIAN : B_ENDIAN)) {
+ if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
}
@@ -1251,7 +1258,7 @@ void blo_freefiledata(FileData *fd)
}
if (fd->strm.next_in) {
- if (inflateEnd (&fd->strm) != Z_OK) {
+ if (inflateEnd(&fd->strm) != Z_OK) {
printf("close gzip stream error\n");
}
}
@@ -1317,6 +1324,7 @@ bool BLO_has_bfile_extension(const char *str)
*
* \param path the full path to explode.
* \param r_dir the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
* \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
* \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
* \return true if path contains a blend file.
@@ -1413,7 +1421,7 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
/* ************** OLD POINTERS ******************* */
-static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
@@ -1430,7 +1438,7 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
* fcurve group pointer and keeps lasthit optimal for linking all further
* fcurves.
*/
-static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */
+static void *newdataadr_ex(FileData *fd, const void *adr, bool increase_lasthit) /* only direct databocks */
{
if (increase_lasthit) {
return newdataadr(fd, adr);
@@ -1443,38 +1451,38 @@ static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* o
}
}
-static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+static void *newglobadr(FileData *fd, const void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
-static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */
{
if (fd->imamap && adr)
return oldnewmap_lookup_and_inc(fd->imamap, adr, true);
return NULL;
}
-static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
+static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
return NULL;
}
-static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */
+static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */
{
if (fd->soundmap && adr)
return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
return NULL;
}
-static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */
+static void *newpackedadr(FileData *fd, const void *adr) /* used to restore packed data after undo */
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
@@ -1483,17 +1491,17 @@ static void *newpackedadr(FileData *fd, void *adr) /* used to restore packe
}
-static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return newlibadr(fd, lib, adr);
}
-static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
ID *id = newlibadr(fd, lib, adr);
@@ -1502,15 +1510,27 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user
return id;
}
-void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
return newlibadr_us(fd, lib, adr);
}
-static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr) /* ensures real user */
+{
+ ID *id = newlibadr(fd, lib, adr);
+
+ id_us_ensure_real(id);
+
+ return id;
+}
+
+static void change_idid_adr_fd(FileData *fd, const void *old, void *new)
{
int i;
+ /* use a binary search if we have a sorted libmap, for now it's not needed. */
+ BLI_assert(fd->libmap->sorted == false);
+
for (i = 0; i < fd->libmap->nentries; i++) {
OldNew *entry = &fd->libmap->entries[i];
@@ -2165,9 +2185,10 @@ static void lib_link_brush(FileData *fd, Main *main)
if (brush->id.tag & LIB_TAG_NEED_LINK) {
brush->id.tag &= ~LIB_TAG_NEED_LINK;
+ /* brush->(mask_)mtex.obj is ignored on purpose? */
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
- brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
+ brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image);
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
}
@@ -3798,7 +3819,7 @@ static void lib_link_texture(FileData *fd, Main *main)
lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
- tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo);
+ tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system
if (tex->env)
tex->env->object = newlibadr(fd, tex->id.lib, tex->env->object);
if (tex->pd)
@@ -3882,7 +3903,7 @@ static void lib_link_material(FileData *fd, Main *main)
* of library blocks that implement this.*/
IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo);
+ ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
for (a = 0; a < MAX_MTEX; a++) {
@@ -3951,7 +3972,7 @@ static void direct_link_pointcache_cb(FileData *fd, void *data)
/* the cache saves non-struct data without DNA */
if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
- int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
+ int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
int *poin = pm->data[i];
BLI_endian_switch_int32_array(poin, tot);
@@ -4035,9 +4056,13 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
lib_link_partdeflect(fd, &part->id, part->pd);
lib_link_partdeflect(fd, &part->id, part->pd2);
- if (part->effector_weights)
+ if (part->effector_weights) {
part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
-
+ }
+ else {
+ part->effector_weights = BKE_add_effector_weights(part->eff_group);
+ }
+
if (part->dupliweights.first && part->dup_group) {
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
@@ -4285,8 +4310,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
* little bogus; it would be better if each mesh consistently added one ref
* to each image it used. - z0r */
for (i = 0; i < totface; i++, tf++) {
- tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
- id_us_ensure_real(&tf->tpage->id);
+ tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
}
}
@@ -4314,8 +4338,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata
int j;
for (j = 0; j < totface; j++, tf++) {
- tf->tpage = newlibadr(fd, me->id.lib, tf->tpage);
- id_us_ensure_real((ID *)tf->tpage);
+ tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
}
}
}
@@ -4865,7 +4888,7 @@ static void lib_link_object(FileData *fd, Main *main)
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss)
- fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo);
+ fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); // XXX deprecated - old animation system
}
{
@@ -4904,6 +4927,7 @@ static void lib_link_object(FileData *fd, Main *main)
{
ob->probe = newlibadr(fd, ob->id.lib, ob->probe);
ob->parallaxcorrect = newlibadr(fd, ob->id.lib, ob->parallaxcorrect);
+ ob->reflectionplane = newlibadr(fd, ob->id.lib, ob->reflectionplane);
BLI_listbase_clear(&ob->gpuprobe);
}
}
@@ -5610,7 +5634,6 @@ static void lib_link_scene(FileData *fd, Main *main)
for (base = sce->base.first; base; base = next) {
next = base->next;
- /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */
base->object = newlibadr_us(fd, sce->id.lib, base->object);
if (base->object == NULL) {
@@ -5624,7 +5647,7 @@ static void lib_link_scene(FileData *fd, Main *main)
SEQ_BEGIN (sce->ed, seq)
{
- if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo);
+ if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system
seq->scene_sound = NULL;
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
@@ -6264,8 +6287,8 @@ static void lib_link_screen(FileData *fd, Main *main)
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- sima->image = newlibadr_us(fd, sc->id.lib, sima->image);
- sima->mask_info.mask = newlibadr_us(fd, sc->id.lib, sima->mask_info.mask);
+ sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image);
+ sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask);
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so fingers crossed this works fine!
@@ -6371,8 +6394,8 @@ static void lib_link_screen(FileData *fd, Main *main)
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->clip = newlibadr_us(fd, sc->id.lib, sclip->clip);
- sclip->mask_info.mask = newlibadr_us(fd, sc->id.lib, sclip->mask_info.mask);
+ sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip);
+ sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask);
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
@@ -6392,68 +6415,96 @@ typedef enum ePointerUserMode {
USER_REAL = 1, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
-static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
+static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user)
{
- if (STREQ(newid->name + 2, id->name + 2)) {
- if (newid->lib == id->lib) {
- if (user == USER_REAL) {
- id_us_ensure_real(newid);
+ BLI_assert(STREQ(newid->name + 2, id->name + 2));
+ BLI_assert(newid->lib == id->lib);
+ UNUSED_VARS_NDEBUG(id);
+
+ if (user == USER_REAL) {
+ id_us_ensure_real(newid);
+ }
+}
+
+#ifndef USE_GHASH_RESTORE_POINTER
+/**
+ * A version of #restore_pointer_by_name that performs a full search (slow!).
+ * Use only for limited lookups, when the overhead of
+ * creating a #IDNameLib_Map for a single lookup isn't worthwhile.
+ */
+static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user)
+{
+ if (id) {
+ ListBase *lb = which_libbase(mainp, GS(id->name));
+ if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */
+ ID *idn = lb->first;
+ for (; idn; idn = idn->next) {
+ if (STREQ(idn->name + 2, id->name + 2)) {
+ if (idn->lib == id->lib) {
+ restore_pointer_user(id, idn, user);
+ break;
+ }
+ }
}
- return true;
+ return idn;
}
}
- return false;
+ return NULL;
}
+#endif
/**
* Only for undo files, or to restore a screen after reading without UI...
*
- * user
+ * \param user:
* - USER_IGNORE: no usercount change
* - USER_REAL: ensure a real user (even if a fake one is set)
+ * \param id_map: lookup table, use when performing many lookups.
+ * this could be made an optional argument (falling back to a full lookup),
+ * however at the moment it's always available.
*/
-static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
+static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user)
{
+#ifdef USE_GHASH_RESTORE_POINTER
if (id) {
- ListBase *lb = which_libbase(mainp, GS(id->name));
- if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
- ID *idn = lb->first;
-
- for (; idn; idn = idn->next) {
- if (restore_pointer(id, idn, user))
- break;
- }
-
- return idn;
+ /* use fast lookup when available */
+ ID *idn = BKE_main_idmap_lookup_id(id_map, id);
+ if (idn) {
+ restore_pointer_user(id, idn, user);
}
+ return idn;
}
return NULL;
+#else
+ Main *mainp = BKE_main_idmap_main_get(id_map);
+ return restore_pointer_by_name_main(mainp, id, user);
+#endif
}
-static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain)
+static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map)
{
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != NULL);
- id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL);
+ id->newid = restore_pointer_by_name(id_map, id->newid, USER_REAL);
}
}
static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
{
- Main *newmain = (Main *)arg_pt;
+ struct IDNameLib_Map *id_map = arg_pt;
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->clip, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->mask, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->sound, id_map);
return 1;
}
-static void lib_link_clipboard_restore(Main *newmain)
+static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
{
/* update IDs stored in sequencer clipboard */
- BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain);
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
/* called from kernel/blender.c */
@@ -6465,11 +6516,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
wmWindowManager *wm;
bScreen *sc;
ScrArea *sa;
-
+
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
/* first windowmanager */
for (wm = newmain->wm.first; wm; wm = wm->id.next) {
for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL);
+ win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
if (win->screen == NULL)
win->screen = curscreen;
@@ -6482,7 +6535,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
for (sc = newmain->screen.first; sc; sc = sc->id.next) {
Scene *oldscene = sc->scene;
- sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL);
+ sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
if (sc->scene == NULL)
sc->scene = curscene;
@@ -6501,16 +6554,16 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (v3d->scenelock)
v3d->camera = NULL; /* always get from scene */
else
- v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL);
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
- v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL);
+ v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
- if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
+ if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) {
id_us_plus((ID *)bgpic->ima);
}
- if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) {
+ if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) {
id_us_plus((ID *)bgpic->clip);
}
}
@@ -6554,10 +6607,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bDopeSheet *ads = sipo->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
/* force recalc of list of channels (i.e. includes calculating F-Curve colors)
@@ -6567,7 +6620,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
+ sbuts->pinid = restore_pointer_by_name(id_map, sbuts->pinid, USER_IGNORE);
if (sbuts->pinid == NULL) {
sbuts->flag &= ~SB_PIN_CONTEXT;
}
@@ -6584,11 +6637,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
- saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL);
- saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL);
+ saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL);
+ saction->ads.source = restore_pointer_by_name(id_map, (ID *)saction->ads.source, USER_REAL);
if (saction->ads.filter_grp)
- saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE);
+ saction->ads.filter_grp = restore_pointer_by_name(id_map, (ID *)saction->ads.filter_grp, USER_IGNORE);
/* force recalc of list of channels, potentially updating the active action
@@ -6599,7 +6652,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL);
+ sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL);
/* this will be freed, not worth attempting to find same scene,
* since it gets initialized later */
@@ -6614,8 +6667,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL);
- sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL);
+ sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL);
+ sima->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sima->mask_info.mask, USER_REAL);
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -6623,29 +6676,29 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL);
+ sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
- st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL);
+ st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_REAL);
if (st->text == NULL) st->text = newmain->text.first;
}
else if (sl->spacetype == SPACE_SCRIPT) {
SpaceScript *scpt = (SpaceScript *)sl;
- scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL);
+ scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL);
/*sc->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
@@ -6655,7 +6708,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so= (SpaceOops *)sl;
- so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE);
+ so->search_tse.id = restore_pointer_by_name(id_map, so->search_tse.id, USER_IGNORE);
if (so->treestore) {
TreeStoreElem *tselem;
@@ -6665,7 +6718,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
while ((tselem = BLI_mempool_iterstep(&iter))) {
/* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */
if (TSE_IS_REAL_ID(tselem)) {
- tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
+ tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE);
}
else {
tselem->id = NULL;
@@ -6683,14 +6736,14 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
- snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL);
- snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE);
+ snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
+ snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
ntree = nodetree_from_id(snode->id);
if (ntree)
snode->nodetree = ntree;
else
- snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL);
+ snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -6698,7 +6751,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
path->nodetree = snode->nodetree;
}
else
- path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL);
+ path->nodetree= restore_pointer_by_name(id_map, (ID*)path->nodetree, USER_REAL);
if (!path->nodetree)
break;
@@ -6724,22 +6777,24 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL);
- sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL);
+ sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL);
+ sclip->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sclip->mask_info.mask, USER_REAL);
sclip->scopes.ok = 0;
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
- slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL);
+ slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL);
}
}
}
}
/* update IDs stored in all possible clipboards */
- lib_link_clipboard_restore(newmain);
+ lib_link_clipboard_restore(id_map);
+
+ BKE_main_idmap_destroy(id_map);
}
static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
@@ -7001,11 +7056,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
}
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
-
- sima->cumap = newdataadr(fd, sima->cumap);
- if (sima->cumap)
- direct_link_curvemapping(fd, sima->cumap);
-
+
sima->iuser.scene = NULL;
sima->iuser.ok = 1;
sima->scopes.waveform_1 = NULL;
@@ -7320,12 +7371,11 @@ static void lib_link_group(FileData *fd, Main *main)
add_us = false;
for (go = group->gobject.first; go; go = go->next) {
- go->ob= newlibadr(fd, group->id.lib, go->ob);
+ go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
if (go->ob) {
go->ob->flag |= OB_FROMGROUP;
/* if group has an object, it increments user... */
add_us = true;
- id_us_ensure_real(&go->ob->id);
}
}
if (add_us) {
@@ -7897,7 +7947,7 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short tag, ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -7909,21 +7959,27 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
/* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
* However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
* This leads e.g. to desappearing objects in some undo/redo case, see T34446.
- * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
- * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
const char *idname = bhead_id_name(fd, bhead);
- /* printf("Checking %s...\n", idname); */
+#ifdef PRINT_DEBUG
+ printf("Checking %s...\n", idname);
+#endif
if (bhead->code == ID_LI) {
Main *libmain = fd->old_mainlist->first;
/* Skip oldmain itself... */
for (libmain = libmain->next; libmain; libmain = libmain->next) {
- /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */
+#ifdef PRINT_DEBUG
+ printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
+#endif
if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
Main *oldmain = fd->old_mainlist->first;
- /* printf("FOUND!\n"); */
+#ifdef PRINT_DEBUG
+ printf("FOUND!\n");
+#endif
/* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
* a missing ID_ID, we need to get the correct lib it is linked to!
* Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
@@ -7937,13 +7993,19 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
}
return blo_nextbhead(fd, bhead);
}
- /* printf("nothing...\n"); */
+#ifdef PRINT_DEBUG
+ printf("nothing...\n");
+#endif
}
}
else {
- /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */
+#ifdef PRINT_DEBUG
+ printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>");
+#endif
if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
- /* printf("FOUND!\n"); */
+#ifdef PRINT_DEBUG
+ printf("FOUND!\n");
+#endif
/* Even though we found our linked ID, there is no guarantee its address is still the same... */
if (id != bhead->old) {
oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
@@ -7955,7 +8017,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
}
return blo_nextbhead(fd, bhead);
}
- /* printf("nothing...\n"); */
+#ifdef PRINT_DEBUG
+ printf("nothing...\n");
+#endif
}
}
@@ -7983,7 +8047,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
if (!id)
return blo_nextbhead(fd, bhead);
- id->tag = flag | LIB_TAG_NEED_LINK;
+ id->tag = tag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
@@ -8241,6 +8305,9 @@ 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! */
@@ -8469,7 +8536,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
struct BHeadSort {
BHead *bhead;
- void *old;
+ const void *old;
};
static int verg_bheadsort(const void *v1, const void *v2)
@@ -9275,6 +9342,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
expand_doit(fd, mainvar, ob->probe);
expand_doit(fd, mainvar, ob->parallaxcorrect);
+ expand_doit(fd, mainvar, ob->reflectionplane);
}
static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
@@ -9664,16 +9732,16 @@ static void give_base_to_groups(
}
}
-static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const short tag)
{
- const short idcode = GS(idname);
ListBase *lb = which_libbase(mainvar, idcode);
ID *ph_id = BKE_libblock_alloc_notest(idcode);
- memcpy(ph_id->name, idname, sizeof(ph_id->name));
+ *((short *)ph_id->name) = idcode;
+ BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
BKE_libblock_init_empty(ph_id);
ph_id->lib = mainvar->curlib;
- ph_id->tag = flag | LIB_TAG_MISSING;
+ ph_id->tag = tag | LIB_TAG_MISSING;
ph_id->us = ID_FAKE_USERS(ph_id);
ph_id->icon_id = 0;
@@ -9685,7 +9753,9 @@ static ID *create_placeholder(Main *mainvar, const char *idname, const short fla
/* returns true if the item was found
* but it may already have already been appended/linked */
-static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name)
+static ID *link_named_part(
+ Main *mainl, FileData *fd, const short idcode, const char *name,
+ const bool use_placeholders, const bool force_indirect)
{
BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
ID *id;
@@ -9696,7 +9766,7 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
- read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id);
+ read_libblock(fd, mainl, bhead, force_indirect ? LIB_TAG_TESTIND : LIB_TAG_TESTEXT, &id);
if (id) {
/* sort by name in list */
@@ -9709,18 +9779,22 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const
if (G.debug)
printf("append: already linked\n");
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
- if (id->tag & LIB_TAG_INDIRECT) {
+ if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
id->tag |= LIB_TAG_EXTERN;
}
}
}
+ else if (use_placeholders) {
+ /* XXX flag part is weak! */
+ id = create_placeholder(mainl, idcode, name, force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN);
+ }
else {
id = NULL;
}
/* if we found the id but the id is NULL, this is really bad */
- BLI_assert((bhead != NULL) == (id != NULL));
+ BLI_assert(!((bhead != NULL) && (id == NULL)));
return id;
}
@@ -9792,9 +9866,9 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
static ID *link_named_part_ex(
Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
- Scene *scene, View3D *v3d)
+ Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
{
- ID *id = link_named_part(mainl, fd, idcode, name);
+ ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
link_object_postprocess(id, scene, v3d, flag);
@@ -9820,7 +9894,7 @@ static ID *link_named_part_ex(
ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part(mainl, fd, idcode, name);
+ return link_named_part(mainl, fd, idcode, name, false, false);
}
/**
@@ -9834,15 +9908,18 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
* \param flag Options for linking, used for instantiating.
* \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
* \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file.
+ * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only).
* \return the linked ID when found.
*/
ID *BLO_library_link_named_part_ex(
Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const short flag,
- Scene *scene, View3D *v3d)
+ Scene *scene, View3D *v3d,
+ const bool use_placeholders, const bool force_indirect)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect);
}
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@ -9882,7 +9959,7 @@ static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *i
/* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
if (r_id) {
- *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL;
+ *r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL;
}
}
}
@@ -10012,21 +10089,22 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
/* ************* READ LIBRARY ************** */
-static int mainvar_count_libread_blocks(Main *mainvar)
+static int mainvar_id_tag_any_check(Main *mainvar, const short tag)
{
ListBase *lbarray[MAX_LIBARRAY];
- int a, tot = 0;
+ int a;
a = set_listbasepointers(mainvar, lbarray);
while (a--) {
ID *id;
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_READ)
- tot++;
+ if (id->tag & tag) {
+ return true;
+ }
}
}
- return tot;
+ return false;
}
static void read_libraries(FileData *basefd, ListBase *mainlist)
@@ -10046,10 +10124,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* test 1: read libdata */
mainptr= mainl->next;
while (mainptr) {
- int tot = mainvar_count_libread_blocks(mainptr);
-
- // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
- if (tot) {
+ if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) {
+ // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
+
FileData *fd = mainptr->curlib->filedata;
if (fd == NULL) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index f5c19f5ee22..42728fd406f 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -156,9 +156,9 @@ const char *bhead_id_name(const FileData *fd, const BHead *bhead);
void blo_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, void *oldaddr, void *newaddr, int nr);
-void *blo_do_versions_newlibadr(struct FileData *fd, void *lib, void *adr);
-void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr);
+void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr);
+void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
+void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
struct PartEff *blo_do_version_give_parteff_245(struct Object *ob);
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index d81cd6a6c60..2a6c88f4922 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1212,9 +1212,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
- }
- {
for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
@@ -1223,5 +1221,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_NormalEdit) {
+ NormalEditModifierData *nemd = (NormalEditModifierData *)md;
+ nemd->mix_limit = DEG2RADF(180.0f);
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index d3c418dd72c..bc91ea8779a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -29,15 +29,22 @@
*/
-/*
- * FILEFORMAT: IFF-style structure (but not IFF compatible!)
+/**
+ *
+ * FILE FORMAT
+ * ===========
+ *
+ * IFF-style structure (but not IFF compatible!)
*
* start file:
+ * <pre>
* BLENDER_V100 12 bytes (versie 1.00)
* V = big endian, v = little endian
* _ = 4 byte pointer, - = 8 byte pointer
+ * </pre>
*
- * datablocks: also see struct BHead
+ * datablocks: (also see struct #BHead).
+ * <pre>
* <bh.code> 4 chars
* <bh.len> int, len data after BHead
* <bh.old> void, old pointer
@@ -46,29 +53,32 @@
* data
* ...
* ...
+ * </pre>
*
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with StructDNA .
*
+ *
* WRITE
+ * =====
*
* Preferred writing order: (not really a must, but why would you do it random?)
* Any case: direct data is ALWAYS after the lib block
*
* (Local file data)
* - for each LibBlock
- * - write LibBlock
- * - write associated direct data
+ * - write LibBlock
+ * - write associated direct data
* (External file data)
* - per library
- * - write library block
- * - per LibBlock
- * - write the ID of LibBlock
- * - write TEST (128x128, blend file preview, optional)
- * - write FileGlobal (some global vars)
- * - write SDNA
- * - write USER if filename is ~/X.XX/config/startup.blend
+ * - write library block
+ * - per LibBlock
+ * - write the ID of LibBlock
+ * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
+ * - write #GLOB (#FileGlobal struct) (some global vars).
+ * - write #DNA1 (#SDNA struct)
+ * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``.
*/
@@ -163,7 +173,7 @@
#include "BKE_mesh.h"
#ifdef USE_NODE_COMPAT_CUSTOMNODES
-#include "NOD_socket.h" /* for sock->default_value data */
+#include "NOD_socket.h" /* for sock->default_value data */
#endif
@@ -174,6 +184,9 @@
#include "readfile.h"
+/* for SDNA_TYPE_FROM_STRUCT() macro */
+#include "dna_type_offsets.h"
+
#include <errno.h>
/* ********* my write, buffered writing with minimum size chunks ************ */
@@ -294,8 +307,9 @@ typedef struct {
unsigned char *buf;
MemFile *compare, *current;
-
- int tot, count, error;
+
+ int tot, count;
+ bool error;
/* Wrap writing, so we can use zlib or
* other compression types later, see: G_FILE_COMPRESS
@@ -303,33 +317,32 @@ typedef struct {
WriteWrap *ww;
#ifdef USE_BMESH_SAVE_AS_COMPAT
- char use_mesh_compat; /* option to save with older mesh format */
+ bool use_mesh_compat; /* option to save with older mesh format */
#endif
} WriteData;
static WriteData *writedata_new(WriteWrap *ww)
{
- WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
-
- /* XXX, see note about this in readfile.c, remove
- * once we have an xp lock - zr
- */
-
- if (wd == NULL) return NULL;
+ WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
wd->ww = ww;
- wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
+ wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
return wd;
}
static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
{
- if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return;
- if (wd->error) return;
+ if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) {
+ return;
+ }
+
+ if (UNLIKELY(wd->error)) {
+ return;
+ }
/* memory based save */
if (wd->current) {
@@ -337,7 +350,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
}
else {
if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
- wd->error = 1;
+ wd->error = true;
}
}
}
@@ -358,34 +371,36 @@ static void writedata_free(WriteData *wd)
* \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 (wd->error) return;
+ if (UNLIKELY(wd->error)) {
+ return;
+ }
/* flush helps compression for undo-save */
- if (adr==MYWRITE_FLUSH) {
+ if (adr == MYWRITE_FLUSH) {
if (wd->count) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
return;
}
- wd->tot+= len;
-
+ wd->tot += len;
+
/* if we have a single big chunk, write existing data in
* buffer and write out big chunk in smaller pieces */
- if (len>MYWRITE_MAX_CHUNK) {
+ if (len > MYWRITE_MAX_CHUNK) {
if (wd->count) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
do {
- int writelen= MIN2(len, MYWRITE_MAX_CHUNK);
+ int writelen = MIN2(len, MYWRITE_MAX_CHUNK);
writedata_do_write(wd, adr, writelen);
adr = (const char *)adr + writelen;
len -= writelen;
@@ -395,14 +410,14 @@ static void mywrite(WriteData *wd, const void *adr, int len)
}
/* if data would overflow buffer, write out the buffer */
- if (len+wd->count>MYWRITE_BUFFER_SIZE-1) {
+ if (len + wd->count > MYWRITE_BUFFER_SIZE - 1) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
/* append data at end of buffer */
memcpy(&wd->buf[wd->count], adr, len);
- wd->count+= len;
+ wd->count += len;
}
/**
@@ -414,15 +429,17 @@ static void mywrite(WriteData *wd, const void *adr, int len)
*/
static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
{
- WriteData *wd= writedata_new(ww);
+ WriteData *wd = writedata_new(ww);
- if (wd == NULL) return NULL;
+ if (wd == NULL) {
+ return NULL;
+ }
- wd->compare= compare;
- wd->current= current;
+ wd->compare = compare;
+ wd->current = current;
/* this inits comparing */
memfile_chunk_add(compare, NULL, NULL, 0);
-
+
return wd;
}
@@ -432,16 +449,14 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
* \return unknown global variable otherwise
* \warning Talks to other functions with global parameters
*/
-static int endwrite(WriteData *wd)
+static bool endwrite(WriteData *wd)
{
- int err;
-
if (wd->count) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
-
- err= wd->error;
+
+ const bool err = wd->error;
writedata_free(wd);
return err;
@@ -449,51 +464,82 @@ static int endwrite(WriteData *wd)
/* ********** WRITE FILE ****************** */
-static void writestruct_at_address(WriteData *wd, int filecode, const char *structname, int nr, void *adr, void *data)
+static void writestruct_at_address_nr(
+ WriteData *wd, int filecode, const int struct_nr, int nr,
+ const void *adr, const void *data)
{
BHead bh;
const short *sp;
- if (adr==NULL || data==NULL || nr==0) return;
+ BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX);
- /* init BHead */
- bh.code= filecode;
- bh.old= adr;
- bh.nr= nr;
-
- bh.SDNAnr= DNA_struct_find_nr(wd->sdna, structname);
- if (bh.SDNAnr== -1) {
- printf("error: can't find SDNA code <%s>\n", structname);
+ if (adr == NULL || data == NULL || nr == 0) {
return;
}
- sp= wd->sdna->structs[bh.SDNAnr];
- bh.len= nr*wd->sdna->typelens[sp[0]];
+ /* init BHead */
+ bh.code = filecode;
+ bh.old = adr;
+ bh.nr = nr;
+
+ bh.SDNAnr = struct_nr;
+ sp = wd->sdna->structs[bh.SDNAnr];
- if (bh.len==0) return;
+ bh.len = nr * wd->sdna->typelens[sp[0]];
+
+ if (bh.len == 0) {
+ return;
+ }
mywrite(wd, &bh, sizeof(BHead));
mywrite(wd, data, bh.len);
}
-static void writestruct(WriteData *wd, int filecode, const char *structname, int nr, void *adr)
+static void writestruct_at_address_id(
+ WriteData *wd, int filecode, const char *structname, int nr,
+ const void *adr, const void *data)
+{
+ if (adr == NULL || data == NULL || nr == 0) {
+ return;
+ }
+
+ const int SDNAnr = DNA_struct_find_nr(wd->sdna, structname);
+ if (UNLIKELY(SDNAnr == -1)) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+
+ writestruct_at_address_nr(wd, filecode, SDNAnr, nr, adr, data);
+}
+
+static void writestruct_nr(
+ WriteData *wd, int filecode, const int struct_nr, int nr,
+ const void *adr)
{
- writestruct_at_address(wd, filecode, structname, nr, adr, adr);
+ writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr);
+}
+
+static void writestruct_id(
+ WriteData *wd, int filecode, const char *structname, int nr,
+ const void *adr)
+{
+ writestruct_at_address_id(wd, filecode, structname, nr, adr, adr);
}
static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* do not use for structs */
{
BHead bh;
- if (adr==NULL) return;
- if (len==0) return;
+ if (adr == NULL || len == 0) {
+ return;
+ }
/* align to 4 (writes uninitialized bytes in some cases) */
len = (len + 3) & ~3;
/* init BHead */
bh.code = filecode;
- bh.old = (void *)adr; /* this is safe to cast from const */
+ bh.old = adr;
bh.nr = 1;
bh.SDNAnr = 0;
bh.len = len;
@@ -503,68 +549,99 @@ static void writedata(WriteData *wd, int filecode, int len, const void *adr) /*
}
/* use this to force writing of lists in same order as reading (using link_list) */
-static void writelist(WriteData *wd, int filecode, const char *structname, ListBase *lb)
+static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb)
{
- Link *link = lb->first;
-
+ const Link *link = lb->first;
+
while (link) {
- writestruct(wd, filecode, structname, 1, link);
+ writestruct_nr(wd, filecode, struct_nr, 1, link);
link = link->next;
}
}
+#if 0
+static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb)
+{
+ const Link *link = lb->first;
+ if (link) {
+
+ const int struct_nr = DNA_struct_find_nr(wd->sdna, structname);
+ if (struct_nr == -1) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+
+ while (link) {
+ writestruct_nr(wd, filecode, struct_nr, 1, link);
+ link = link->next;
+ }
+ }
+}
+#endif
+
+#define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \
+ writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data)
+
+#define writestruct(wd, filecode, struct_id, nr, adr) \
+ writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr)
+
+#define writelist(wd, filecode, struct_id, lb) \
+ writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb)
+
/* *************** writing some direct data structs used in more code parts **************** */
/*These functions are used by blender's .blend system for file saving/loading.*/
-void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
-void IDP_WriteProperty(IDProperty *prop, void *wd);
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd);
+void IDP_WriteProperty(const IDProperty *prop, void *wd);
-static void IDP_WriteArray(IDProperty *prop, void *wd)
+static void IDP_WriteArray(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
if (prop->subtype == IDP_GROUP) {
- IDProperty **array= prop->data.pointer;
+ IDProperty **array = prop->data.pointer;
int a;
- for (a=0; a<prop->len; a++)
+ for (a = 0; a < prop->len; a++) {
IDP_WriteProperty(array[a], wd);
+ }
}
}
}
-static void IDP_WriteIDPArray(IDProperty *prop, void *wd)
+static void IDP_WriteIDPArray(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
- IDProperty *array = prop->data.pointer;
+ const IDProperty *array = prop->data.pointer;
int a;
- writestruct(wd, DATA, "IDProperty", prop->len, array);
+ writestruct(wd, DATA, IDProperty, prop->len, array);
- for (a=0; a<prop->len; a++)
+ for (a = 0; a < prop->len; a++) {
IDP_WriteProperty_OnlyData(&array[a], wd);
+ }
}
}
-static void IDP_WriteString(IDProperty *prop, void *wd)
+static void IDP_WriteString(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
writedata(wd, DATA, prop->len, prop->data.pointer);
}
-static void IDP_WriteGroup(IDProperty *prop, void *wd)
+static void IDP_WriteGroup(const IDProperty *prop, void *wd)
{
IDProperty *loop;
- for (loop=prop->data.group.first; loop; loop=loop->next) {
+ for (loop = prop->data.group.first; loop; loop = loop->next) {
IDP_WriteProperty(loop, wd);
}
}
/* Functions to read/write ID Properties */
-void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd)
{
switch (prop->type) {
case IDP_GROUP:
@@ -582,35 +659,38 @@ void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
}
}
-void IDP_WriteProperty(IDProperty *prop, void *wd)
+void IDP_WriteProperty(const IDProperty *prop, void *wd)
{
- writestruct(wd, DATA, "IDProperty", 1, prop);
+ writestruct(wd, DATA, IDProperty, 1, prop);
IDP_WriteProperty_OnlyData(prop, wd);
}
-static void write_previews(WriteData *wd, PreviewImage *prv)
+static void write_iddata(void *wd, const ID *id)
+{
+ /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
+ if (id->properties && !ELEM(GS(id->name), ID_WM)) {
+ IDP_WriteProperty(id->properties, wd);
+ }
+}
+
+static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
{
/* Never write previews when doing memsave (i.e. undo/redo)! */
- if (prv && !wd->current) {
- short w = prv->w[1];
- short h = prv->h[1];
- unsigned int *rect = prv->rect[1];
+ if (prv_orig && !wd->current) {
+ PreviewImage prv = *prv_orig;
/* don't write out large previews if not requested */
if (!(U.flag & USER_SAVE_PREVIEWS)) {
- prv->w[1] = 0;
- prv->h[1] = 0;
- prv->rect[1] = NULL;
+ prv.w[1] = 0;
+ prv.h[1] = 0;
+ prv.rect[1] = NULL;
}
- writestruct(wd, DATA, "PreviewImage", 1, prv);
- if (prv->rect[0]) writedata(wd, DATA, prv->w[0] * prv->h[0] * sizeof(unsigned int), prv->rect[0]);
- if (prv->rect[1]) writedata(wd, DATA, prv->w[1] * prv->h[1] * sizeof(unsigned int), prv->rect[1]);
-
- /* restore preview, we still want to keep it in memory even if not saved to file */
- if (!(U.flag & USER_SAVE_PREVIEWS) ) {
- prv->w[1] = w;
- prv->h[1] = h;
- prv->rect[1] = rect;
+ writestruct_at_address(wd, DATA, PreviewImage, 1, prv_orig, &prv);
+ if (prv.rect[0]) {
+ writedata(wd, DATA, prv.w[0] * prv.h[0] * sizeof(unsigned int), prv.rect[0]);
+ }
+ if (prv.rect[1]) {
+ writedata(wd, DATA, prv.w[1] * prv.h[1] * sizeof(unsigned int), prv.rect[1]);
}
}
}
@@ -618,45 +698,47 @@ static void write_previews(WriteData *wd, PreviewImage *prv)
static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
{
FModifier *fcm;
-
+
/* Write all modifiers first (for faster reloading) */
- writelist(wd, DATA, "FModifier", fmodifiers);
-
+ writelist(wd, DATA, FModifier, fmodifiers);
+
/* Modifiers */
- for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
- const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
+ for (fcm = fmodifiers->first; fcm; fcm = fcm->next) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+
/* Write the specific data */
if (fmi && fcm->data) {
/* firstly, just write the plain fmi->data struct */
- writestruct(wd, DATA, fmi->structName, 1, fcm->data);
-
+ writestruct_id(wd, DATA, fmi->structName, 1, fcm->data);
+
/* do any modifier specific stuff */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
+ FMod_Generator *data = fcm->data;
+
/* write coefficients array */
- if (data->coefficients)
- writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
+ if (data->coefficients) {
+ writedata(wd, DATA, sizeof(float) * (data->arraysize), data->coefficients);
+ }
break;
}
case FMODIFIER_TYPE_ENVELOPE:
{
- FMod_Envelope *data= (FMod_Envelope *)fcm->data;
-
+ FMod_Envelope *data = fcm->data;
+
/* write envelope data */
- if (data->data)
- writestruct(wd, DATA, "FCM_EnvelopeData", data->totvert, data->data);
+ if (data->data) {
+ writestruct(wd, DATA, FCM_EnvelopeData, data->totvert, data->data);
+ }
break;
}
case FMODIFIER_TYPE_PYTHON:
{
- FMod_Python *data = (FMod_Python *)fcm->data;
-
+ FMod_Python *data = fcm->data;
+
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
@@ -671,37 +753,41 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
static void write_fcurves(WriteData *wd, ListBase *fcurves)
{
FCurve *fcu;
-
- writelist(wd, DATA, "FCurve", fcurves);
- for (fcu=fcurves->first; fcu; fcu=fcu->next) {
+
+ writelist(wd, DATA, FCurve, fcurves);
+ for (fcu = fcurves->first; fcu; fcu = fcu->next) {
/* curve data */
- if (fcu->bezt)
- writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt);
- if (fcu->fpt)
- writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt);
-
- if (fcu->rna_path)
- writedata(wd, DATA, strlen(fcu->rna_path)+1, fcu->rna_path);
-
+ if (fcu->bezt) {
+ writestruct(wd, DATA, BezTriple, fcu->totvert, fcu->bezt);
+ }
+ if (fcu->fpt) {
+ writestruct(wd, DATA, FPoint, fcu->totvert, fcu->fpt);
+ }
+
+ if (fcu->rna_path) {
+ writedata(wd, DATA, strlen(fcu->rna_path) + 1, fcu->rna_path);
+ }
+
/* driver data */
if (fcu->driver) {
- ChannelDriver *driver= fcu->driver;
+ ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
-
- writestruct(wd, DATA, "ChannelDriver", 1, driver);
-
+
+ writestruct(wd, DATA, ChannelDriver, 1, driver);
+
/* variables */
- writelist(wd, DATA, "DriverVar", &driver->variables);
- for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ writelist(wd, DATA, DriverVar, &driver->variables);
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- if (dtar->rna_path)
- writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path);
+ if (dtar->rna_path) {
+ writedata(wd, DATA, strlen(dtar->rna_path) + 1, dtar->rna_path);
+ }
}
DRIVER_TARGETS_LOOPER_END
}
}
-
+
/* write F-Modifiers */
write_fmodifiers(wd, &fcu->modifiers);
}
@@ -709,27 +795,27 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
static void write_actions(WriteData *wd, ListBase *idbase)
{
- bAction *act;
+ bAction *act;
bActionGroup *grp;
TimeMarker *marker;
-
- for (act=idbase->first; act; act= act->id.next) {
- if (act->id.us>0 || wd->current) {
- writestruct(wd, ID_AC, "bAction", 1, act);
- if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
-
+
+ for (act = idbase->first; act; act = act->id.next) {
+ if (act->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AC, bAction, 1, act);
+ write_iddata(wd, &act->id);
+
write_fcurves(wd, &act->curves);
-
- for (grp=act->groups.first; grp; grp=grp->next) {
- writestruct(wd, DATA, "bActionGroup", 1, grp);
+
+ for (grp = act->groups.first; grp; grp = grp->next) {
+ writestruct(wd, DATA, bActionGroup, 1, grp);
}
-
- for (marker=act->markers.first; marker; marker=marker->next) {
- writestruct(wd, DATA, "TimeMarker", 1, marker);
+
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
}
}
}
-
+
/* flush helps the compression for undo-save */
mywrite(wd, MYWRITE_FLUSH, 0);
}
@@ -738,18 +824,19 @@ static void write_keyingsets(WriteData *wd, ListBase *list)
{
KeyingSet *ks;
KS_Path *ksp;
-
- for (ks= list->first; ks; ks= ks->next) {
+
+ for (ks = list->first; ks; ks = ks->next) {
/* KeyingSet */
- writestruct(wd, DATA, "KeyingSet", 1, ks);
-
+ writestruct(wd, DATA, KeyingSet, 1, ks);
+
/* Paths */
- for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* Path */
- writestruct(wd, DATA, "KS_Path", 1, ksp);
-
- if (ksp->rna_path)
- writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path);
+ writestruct(wd, DATA, KS_Path, 1, ksp);
+
+ if (ksp->rna_path) {
+ writedata(wd, DATA, strlen(ksp->rna_path) + 1, ksp->rna_path);
+ }
}
}
}
@@ -757,13 +844,13 @@ static void write_keyingsets(WriteData *wd, ListBase *list)
static void write_nlastrips(WriteData *wd, ListBase *strips)
{
NlaStrip *strip;
-
- writelist(wd, DATA, "NlaStrip", strips);
- for (strip= strips->first; strip; strip= strip->next) {
+
+ writelist(wd, DATA, NlaStrip, strips);
+ for (strip = strips->first; strip; strip = strip->next) {
/* write the strip's F-Curves and modifiers */
write_fcurves(wd, &strip->fcurves);
write_fmodifiers(wd, &strip->modifiers);
-
+
/* write the strip's children */
write_nlastrips(wd, &strip->strips);
}
@@ -772,12 +859,12 @@ static void write_nlastrips(WriteData *wd, ListBase *strips)
static void write_nladata(WriteData *wd, ListBase *nlabase)
{
NlaTrack *nlt;
-
+
/* write all the tracks */
- for (nlt= nlabase->first; nlt; nlt= nlt->next) {
+ for (nlt = nlabase->first; nlt; nlt = nlt->next) {
/* write the track first */
- writestruct(wd, DATA, "NlaTrack", 1, nlt);
-
+ writestruct(wd, DATA, NlaTrack, 1, nlt);
+
/* write the track's strips */
write_nlastrips(wd, &nlt->strips);
}
@@ -786,38 +873,37 @@ static void write_nladata(WriteData *wd, ListBase *nlabase)
static void write_animdata(WriteData *wd, AnimData *adt)
{
AnimOverride *aor;
-
+
/* firstly, just write the AnimData block */
- writestruct(wd, DATA, "AnimData", 1, adt);
-
+ writestruct(wd, DATA, AnimData, 1, adt);
+
/* write drivers */
write_fcurves(wd, &adt->drivers);
-
+
/* write overrides */
// FIXME: are these needed?
- for (aor= adt->overrides.first; aor; aor= aor->next) {
+ for (aor = adt->overrides.first; aor; aor = aor->next) {
/* overrides consist of base data + rna_path */
- writestruct(wd, DATA, "AnimOverride", 1, aor);
- writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path);
+ writestruct(wd, DATA, AnimOverride, 1, aor);
+ writedata(wd, DATA, strlen(aor->rna_path) + 1, aor->rna_path);
}
-
+
// TODO write the remaps (if they are needed)
-
+
/* write NLA data */
write_nladata(wd, &adt->nla_tracks);
}
static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap)
{
- int a;
-
- for (a = 0; a < CM_TOT; a++)
- writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
+ for (int a = 0; a < CM_TOT; a++) {
+ writestruct(wd, DATA, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve);
+ }
}
static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
{
- writestruct(wd, DATA, "CurveMapping", 1, cumap);
+ writestruct(wd, DATA, CurveMapping, 1, cumap);
write_curvemapping_curves(wd, cumap);
}
@@ -827,14 +913,14 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no
#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* forward compatibility code, so older blenders still open */
sock->stack_type = 1;
-
+
if (node->type == NODE_GROUP) {
bNodeTree *ngroup = (bNodeTree *)node->id;
if (ngroup) {
/* for node groups: look up the deprecated groupsock pointer */
sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
BLI_assert(sock->groupsock != NULL);
-
+
/* node group sockets now use the generic identifier string to verify group nodes,
* old blender uses the own_index.
*/
@@ -844,20 +930,22 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no
#endif
/* actual socket writing */
- writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ writestruct(wd, DATA, bNodeSocket, 1, sock);
- if (sock->prop)
+ if (sock->prop) {
IDP_WriteProperty(sock->prop, wd);
-
- if (sock->default_value)
+ }
+
+ if (sock->default_value) {
writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value);
+ }
}
static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock)
{
#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* forward compatibility code, so older blenders still open */
sock->stack_type = 1;
-
+
/* Reconstruct the deprecated default_value structs in socket interface DNA. */
if (sock->default_value == NULL && sock->typeinfo) {
node_socket_init_default_value(sock);
@@ -865,13 +953,15 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree),
#endif
/* actual socket writing */
- writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ writestruct(wd, DATA, bNodeSocket, 1, sock);
- if (sock->prop)
+ if (sock->prop) {
IDP_WriteProperty(sock->prop, wd);
-
- if (sock->default_value)
+ }
+
+ if (sock->default_value) {
writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value);
+ }
}
/* this is only direct data, tree itself should have been written */
static void write_nodetree(WriteData *wd, bNodeTree *ntree)
@@ -879,64 +969,91 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
bNode *node;
bNodeSocket *sock;
bNodeLink *link;
-
+
/* for link_list() speed, we write per list */
-
- if (ntree->adt) write_animdata(wd, ntree->adt);
-
+
+ if (ntree->adt) {
+ write_animdata(wd, ntree->adt);
+ }
+
for (node = ntree->nodes.first; node; node = node->next) {
- writestruct(wd, DATA, "bNode", 1, node);
+ writestruct(wd, DATA, bNode, 1, node);
- if (node->prop)
+ if (node->prop) {
IDP_WriteProperty(node->prop, wd);
+ }
- for (sock= node->inputs.first; sock; sock= sock->next)
+ for (sock = node->inputs.first; sock; sock = sock->next) {
write_node_socket(wd, ntree, node, sock);
- for (sock= node->outputs.first; sock; sock= sock->next)
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
write_node_socket(wd, ntree, node, sock);
-
- for (link = node->internal_links.first; link; link = link->next)
- writestruct(wd, DATA, "bNodeLink", 1, link);
+ }
+
+ for (link = node->internal_links.first; link; link = link->next) {
+ writestruct(wd, DATA, bNodeLink, 1, link);
+ }
+
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
- if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
+ if ((ntree->type == NTREE_SHADER) &&
+ ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB))
+ {
write_curvemapping(wd, node->storage);
- else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) {
+ }
+ else if (ntree->type == NTREE_SHADER &&
+ (node->type == SH_NODE_SCRIPT))
+ {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- if (nss->bytecode)
- writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ if (nss->bytecode) {
+ writedata(wd, DATA, strlen(nss->bytecode) + 1, nss->bytecode);
+ }
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
- else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
+ else if ((ntree->type == NTREE_COMPOSIT) &&
+ ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
+ {
write_curvemapping(wd, node->storage);
- else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) )
+ }
+ else if ((ntree->type == NTREE_TEXTURE) &&
+ (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME))
+ {
write_curvemapping(wd, node->storage);
- else if (ntree->type==NTREE_COMPOSIT && node->type==CMP_NODE_MOVIEDISTORTION) {
+ }
+ else if ((ntree->type == NTREE_COMPOSIT) &&
+ (node->type == CMP_NODE_MOVIEDISTORTION))
+ {
/* pass */
}
- else
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ else {
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
}
-
- if (node->type==CMP_NODE_OUTPUT_FILE) {
+
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
/* inputs have own storage data */
- for (sock = node->inputs.first; sock; sock = sock->next)
- writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage);
+ }
}
- if (node->type==CMP_NODE_IMAGE) {
+ if (node->type == CMP_NODE_IMAGE) {
/* write extra socket info */
- for (sock = node->outputs.first; sock; sock = sock->next)
- writestruct(wd, DATA, "NodeImageLayer", 1, sock->storage);
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ writestruct(wd, DATA, NodeImageLayer, 1, sock->storage);
+ }
}
}
-
- for (link= ntree->links.first; link; link= link->next)
- writestruct(wd, DATA, "bNodeLink", 1, link);
-
- for (sock = ntree->inputs.first; sock; sock = sock->next)
+
+ for (link = ntree->links.first; link; link = link->next) {
+ writestruct(wd, DATA, bNodeLink, 1, link);
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
write_node_socket_interface(wd, ntree, sock);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
write_node_socket_interface(wd, ntree, sock);
+ }
}
/**
@@ -991,9 +1108,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
/* XXX in future, handle multiple windows with multiple screens? */
current_screen_compat(mainvar, &curscreen, false);
- if (curscreen) curscene = curscreen->scene;
-
- for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
+ if (curscreen) {
+ curscene = curscreen->scene;
+ }
+
+ for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
data.sfra = sce->r.sfra;
data.efra = sce->r.efra;
@@ -1008,9 +1127,10 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi)
{
- writestruct(wd, DATA, "wmKeyMapItem", 1, kmi);
- if (kmi->properties)
+ writestruct(wd, DATA, wmKeyMapItem, 1, kmi);
+ if (kmi->properties) {
IDP_WriteProperty(kmi->properties, wd);
+ }
}
static void write_userdef(WriteData *wd)
@@ -1022,75 +1142,82 @@ static void write_userdef(WriteData *wd)
bAddon *bext;
bPathCompare *path_cmp;
uiStyle *style;
-
- writestruct(wd, USER, "UserDef", 1, &U);
- for (btheme= U.themes.first; btheme; btheme=btheme->next)
- writestruct(wd, DATA, "bTheme", 1, btheme);
+ writestruct(wd, USER, UserDef, 1, &U);
+
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ writestruct(wd, DATA, bTheme, 1, btheme);
+ }
- for (keymap= U.user_keymaps.first; keymap; keymap=keymap->next) {
- writestruct(wd, DATA, "wmKeyMap", 1, keymap);
+ for (keymap = U.user_keymaps.first; keymap; keymap = keymap->next) {
+ writestruct(wd, DATA, wmKeyMap, 1, keymap);
- for (kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
- writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi);
- if (kmdi->remove_item)
+ for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
+ writestruct(wd, DATA, wmKeyMapDiffItem, 1, kmdi);
+ if (kmdi->remove_item) {
write_keymapitem(wd, kmdi->remove_item);
- if (kmdi->add_item)
+ }
+ if (kmdi->add_item) {
write_keymapitem(wd, kmdi->add_item);
+ }
}
- for (kmi=keymap->items.first; kmi; kmi=kmi->next)
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
write_keymapitem(wd, kmi);
+ }
}
- for (bext= U.addons.first; bext; bext=bext->next) {
- writestruct(wd, DATA, "bAddon", 1, bext);
+ for (bext = U.addons.first; bext; bext = bext->next) {
+ writestruct(wd, DATA, bAddon, 1, bext);
if (bext->prop) {
IDP_WriteProperty(bext->prop, wd);
}
}
for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
- writestruct(wd, DATA, "bPathCompare", 1, path_cmp);
+ writestruct(wd, DATA, bPathCompare, 1, path_cmp);
}
-
- for (style= U.uistyles.first; style; style= style->next) {
- writestruct(wd, DATA, "uiStyle", 1, style);
+
+ for (style = U.uistyles.first; style; style = style->next) {
+ writestruct(wd, DATA, uiStyle, 1, style);
}
}
static void write_boid_state(WriteData *wd, BoidState *state)
{
BoidRule *rule = state->rules.first;
- //BoidCondition *cond = state->conditions.first;
- writestruct(wd, DATA, "BoidState", 1, state);
+ writestruct(wd, DATA, BoidState, 1, state);
- for (; rule; rule=rule->next) {
+ for (; rule; rule = rule->next) {
switch (rule->type) {
case eBoidRuleType_Goal:
case eBoidRuleType_Avoid:
- writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule);
+ writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule);
break;
case eBoidRuleType_AvoidCollision:
- writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule);
+ writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule);
break;
case eBoidRuleType_FollowLeader:
- writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule);
+ writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule);
break;
case eBoidRuleType_AverageSpeed:
- writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule);
+ writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule);
break;
case eBoidRuleType_Fight:
- writestruct(wd, DATA, "BoidRuleFight", 1, rule);
+ writestruct(wd, DATA, BoidRuleFight, 1, rule);
break;
default:
- writestruct(wd, DATA, "BoidRule", 1, rule);
+ writestruct(wd, DATA, BoidRule, 1, rule);
break;
}
}
- //for (; cond; cond=cond->next)
- // writestruct(wd, DATA, "BoidCondition", 1, cond);
+#if 0
+ BoidCondition *cond = state->conditions.first;
+ for (; cond; cond = cond->next) {
+ writestruct(wd, DATA, BoidCondition, 1, cond);
+ }
+#endif
}
/* update this also to readfile.c */
@@ -1113,31 +1240,34 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
PointCache *cache = ptcaches->first;
int i;
- for (; cache; cache=cache->next) {
- writestruct(wd, DATA, "PointCache", 1, cache);
+ for (; cache; cache = cache->next) {
+ writestruct(wd, DATA, PointCache, 1, cache);
- if ((cache->flag & PTCACHE_DISK_CACHE)==0) {
+ if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
PTCacheMem *pm = cache->mem_cache.first;
- for (; pm; pm=pm->next) {
+ for (; pm; pm = pm->next) {
PTCacheExtra *extra = pm->extradata.first;
- writestruct(wd, DATA, "PTCacheMem", 1, pm);
-
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (pm->data[i] && pm->data_types & (1<<i)) {
- if (ptcache_data_struct[i][0] == '\0')
+ writestruct(wd, DATA, PTCacheMem, 1, pm);
+
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (pm->data[i] && pm->data_types & (1 << i)) {
+ if (ptcache_data_struct[i][0] == '\0') {
writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
- else
- writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
+ }
+ else {
+ writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
+ }
}
}
- for (; extra; extra=extra->next) {
- if (ptcache_extra_struct[extra->type][0] == '\0')
+ for (; extra; extra = extra->next) {
+ if (ptcache_extra_struct[extra->type][0] == '\0') {
continue;
- writestruct(wd, DATA, "PTCacheExtra", 1, extra);
- writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
+ }
+ writestruct(wd, DATA, PTCacheExtra, 1, extra);
+ writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
}
}
}
@@ -1150,90 +1280,109 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
GroupObject *go;
int a;
- part= idbase->first;
+ part = idbase->first;
while (part) {
- if (part->id.us>0 || wd->current) {
+ if (part->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_PA, "ParticleSettings", 1, part);
- if (part->id.properties) IDP_WriteProperty(part->id.properties, wd);
- if (part->adt) write_animdata(wd, part->adt);
- writestruct(wd, DATA, "PartDeflect", 1, part->pd);
- writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
- writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
-
- if (part->clumpcurve)
+ writestruct(wd, ID_PA, ParticleSettings, 1, part);
+ write_iddata(wd, &part->id);
+
+ if (part->adt) {
+ write_animdata(wd, part->adt);
+ }
+ writestruct(wd, DATA, PartDeflect, 1, part->pd);
+ writestruct(wd, DATA, PartDeflect, 1, part->pd2);
+ writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
+
+ if (part->clumpcurve) {
write_curvemapping(wd, part->clumpcurve);
- if (part->roughcurve)
+ }
+ if (part->roughcurve) {
write_curvemapping(wd, part->roughcurve);
-
+ }
+
dw = part->dupliweights.first;
- for (; dw; dw=dw->next) {
+ for (; dw; dw = dw->next) {
/* update indices */
dw->index = 0;
if (part->dup_group) { /* can be NULL if lining fails or set to None */
go = part->dup_group->gobject.first;
while (go && go->ob != dw->ob) {
- go=go->next;
+ go = go->next;
dw->index++;
}
}
- writestruct(wd, DATA, "ParticleDupliWeight", 1, dw);
+ writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
}
if (part->boids && part->phystype == PART_PHYS_BOIDS) {
BoidState *state = part->boids->states.first;
- writestruct(wd, DATA, "BoidSettings", 1, part->boids);
+ writestruct(wd, DATA, BoidSettings, 1, part->boids);
- for (; state; state=state->next)
+ for (; state; state = state->next) {
write_boid_state(wd, state);
+ }
}
if (part->fluid && part->phystype == PART_PHYS_FLUID) {
- writestruct(wd, DATA, "SPHFluidSettings", 1, part->fluid);
+ writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
}
- for (a=0; a<MAX_MTEX; a++) {
- if (part->mtex[a]) writestruct(wd, DATA, "MTex", 1, part->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, part->mtex[a]);
+ }
}
}
- part= part->id.next;
+ part = part->id.next;
}
}
static void write_particlesystems(WriteData *wd, ListBase *particles)
{
- ParticleSystem *psys= particles->first;
+ ParticleSystem *psys = particles->first;
ParticleTarget *pt;
int a;
- for (; psys; psys=psys->next) {
- writestruct(wd, DATA, "ParticleSystem", 1, psys);
+ for (; psys; psys = psys->next) {
+ writestruct(wd, DATA, ParticleSystem, 1, psys);
if (psys->particles) {
- writestruct(wd, DATA, "ParticleData", psys->totpart, psys->particles);
+ writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles);
if (psys->particles->hair) {
ParticleData *pa = psys->particles;
- for (a=0; a<psys->totpart; a++, pa++)
- writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
+ for (a = 0; a < psys->totpart; a++, pa++) {
+ writestruct(wd, DATA, HairKey, pa->totkey, pa->hair);
+ }
}
- if (psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS)
- writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid);
+ if (psys->particles->boid &&
+ (psys->part->phystype == PART_PHYS_BOIDS))
+ {
+ writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid);
+ }
- if (psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
- writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs);
+ if (psys->part->fluid &&
+ (psys->part->phystype == PART_PHYS_FLUID) &&
+ (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
+ {
+ writestruct(wd, DATA, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
+ }
}
pt = psys->targets.first;
- for (; pt; pt=pt->next)
- writestruct(wd, DATA, "ParticleTarget", 1, pt);
+ for (; pt; pt = pt->next) {
+ writestruct(wd, DATA, ParticleTarget, 1, pt);
+ }
- if (psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild, psys->child);
+ if (psys->child) {
+ writestruct(wd, DATA, ChildParticle, psys->totchild, psys->child);
+ }
if (psys->clmd) {
- writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd);
- writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms);
- writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms);
+ writestruct(wd, DATA, ClothModifierData, 1, psys->clmd);
+ writestruct(wd, DATA, ClothSimSettings, 1, psys->clmd->sim_parms);
+ writestruct(wd, DATA, ClothCollSettings, 1, psys->clmd->coll_parms);
}
write_pointcaches(wd, &psys->ptcaches);
@@ -1244,14 +1393,15 @@ static void write_properties(WriteData *wd, ListBase *lb)
{
bProperty *prop;
- prop= lb->first;
+ prop = lb->first;
while (prop) {
- writestruct(wd, DATA, "bProperty", 1, prop);
+ writestruct(wd, DATA, bProperty, 1, prop);
- if (prop->poin && prop->poin != &prop->data)
+ if (prop->poin && prop->poin != &prop->data) {
writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
+ }
- prop= prop->next;
+ prop = prop->next;
}
}
@@ -1259,57 +1409,57 @@ static void write_sensors(WriteData *wd, ListBase *lb)
{
bSensor *sens;
- sens= lb->first;
+ sens = lb->first;
while (sens) {
- writestruct(wd, DATA, "bSensor", 1, sens);
+ writestruct(wd, DATA, bSensor, 1, sens);
- writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
+ writedata(wd, DATA, sizeof(void *) * sens->totlinks, sens->links);
switch (sens->type) {
- case SENS_NEAR:
- writestruct(wd, DATA, "bNearSensor", 1, sens->data);
- break;
- case SENS_MOUSE:
- writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
- break;
- case SENS_KEYBOARD:
- writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
- break;
- case SENS_PROPERTY:
- writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
- break;
- case SENS_ARMATURE:
- writestruct(wd, DATA, "bArmatureSensor", 1, sens->data);
- break;
- case SENS_ACTUATOR:
- writestruct(wd, DATA, "bActuatorSensor", 1, sens->data);
- break;
- case SENS_DELAY:
- writestruct(wd, DATA, "bDelaySensor", 1, sens->data);
- break;
- case SENS_COLLISION:
- writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
- break;
- case SENS_RADAR:
- writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
- break;
- case SENS_RANDOM:
- writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
- break;
- case SENS_RAY:
- writestruct(wd, DATA, "bRaySensor", 1, sens->data);
- break;
- case SENS_MESSAGE:
- writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
- break;
- case SENS_JOYSTICK:
- writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case SENS_NEAR:
+ writestruct(wd, DATA, bNearSensor, 1, sens->data);
+ break;
+ case SENS_MOUSE:
+ writestruct(wd, DATA, bMouseSensor, 1, sens->data);
+ break;
+ case SENS_KEYBOARD:
+ writestruct(wd, DATA, bKeyboardSensor, 1, sens->data);
+ break;
+ case SENS_PROPERTY:
+ writestruct(wd, DATA, bPropertySensor, 1, sens->data);
+ break;
+ case SENS_ARMATURE:
+ writestruct(wd, DATA, bArmatureSensor, 1, sens->data);
+ break;
+ case SENS_ACTUATOR:
+ writestruct(wd, DATA, bActuatorSensor, 1, sens->data);
+ break;
+ case SENS_DELAY:
+ writestruct(wd, DATA, bDelaySensor, 1, sens->data);
+ break;
+ case SENS_COLLISION:
+ writestruct(wd, DATA, bCollisionSensor, 1, sens->data);
+ break;
+ case SENS_RADAR:
+ writestruct(wd, DATA, bRadarSensor, 1, sens->data);
+ break;
+ case SENS_RANDOM:
+ writestruct(wd, DATA, bRandomSensor, 1, sens->data);
+ break;
+ case SENS_RAY:
+ writestruct(wd, DATA, bRaySensor, 1, sens->data);
+ break;
+ case SENS_MESSAGE:
+ writestruct(wd, DATA, bMessageSensor, 1, sens->data);
+ break;
+ case SENS_JOYSTICK:
+ writestruct(wd, DATA, bJoystickSensor, 1, sens->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- sens= sens->next;
+ sens = sens->next;
}
}
@@ -1317,24 +1467,24 @@ static void write_controllers(WriteData *wd, ListBase *lb)
{
bController *cont;
- cont= lb->first;
+ cont = lb->first;
while (cont) {
- writestruct(wd, DATA, "bController", 1, cont);
+ writestruct(wd, DATA, bController, 1, cont);
- writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
+ writedata(wd, DATA, sizeof(void *) * cont->totlinks, cont->links);
switch (cont->type) {
- case CONT_EXPRESSION:
- writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
- break;
- case CONT_PYTHON:
- writestruct(wd, DATA, "bPythonCont", 1, cont->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case CONT_EXPRESSION:
+ writestruct(wd, DATA, bExpressionCont, 1, cont->data);
+ break;
+ case CONT_PYTHON:
+ writestruct(wd, DATA, bPythonCont, 1, cont->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- cont= cont->next;
+ cont = cont->next;
}
}
@@ -1342,133 +1492,135 @@ static void write_actuators(WriteData *wd, ListBase *lb)
{
bActuator *act;
- act= lb->first;
+ act = lb->first;
while (act) {
- writestruct(wd, DATA, "bActuator", 1, act);
+ writestruct(wd, DATA, bActuator, 1, act);
switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- writestruct(wd, DATA, "bActionActuator", 1, act->data);
- break;
- case ACT_SOUND:
- writestruct(wd, DATA, "bSoundActuator", 1, act->data);
- break;
- case ACT_OBJECT:
- writestruct(wd, DATA, "bObjectActuator", 1, act->data);
- break;
- case ACT_PROPERTY:
- writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
- break;
- case ACT_CAMERA:
- writestruct(wd, DATA, "bCameraActuator", 1, act->data);
- break;
- case ACT_CONSTRAINT:
- writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
- break;
- case ACT_EDIT_OBJECT:
- writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
- break;
- case ACT_SCENE:
- writestruct(wd, DATA, "bSceneActuator", 1, act->data);
- break;
- case ACT_GROUP:
- writestruct(wd, DATA, "bGroupActuator", 1, act->data);
- break;
- case ACT_RANDOM:
- writestruct(wd, DATA, "bRandomActuator", 1, act->data);
- break;
- case ACT_MESSAGE:
- writestruct(wd, DATA, "bMessageActuator", 1, act->data);
- break;
- case ACT_GAME:
- writestruct(wd, DATA, "bGameActuator", 1, act->data);
- break;
- case ACT_VISIBILITY:
- writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
- break;
- case ACT_2DFILTER:
- writestruct(wd, DATA, "bTwoDFilterActuator", 1, act->data);
- break;
- case ACT_PARENT:
- writestruct(wd, DATA, "bParentActuator", 1, act->data);
- break;
- case ACT_STATE:
- writestruct(wd, DATA, "bStateActuator", 1, act->data);
- break;
- case ACT_ARMATURE:
- writestruct(wd, DATA, "bArmatureActuator", 1, act->data);
- break;
- case ACT_STEERING:
- writestruct(wd, DATA, "bSteeringActuator", 1, act->data);
- break;
- case ACT_MOUSE:
- writestruct(wd, DATA, "bMouseActuator", 1, act->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case ACT_ACTION:
+ case ACT_SHAPEACTION:
+ writestruct(wd, DATA, bActionActuator, 1, act->data);
+ break;
+ case ACT_SOUND:
+ writestruct(wd, DATA, bSoundActuator, 1, act->data);
+ break;
+ case ACT_OBJECT:
+ writestruct(wd, DATA, bObjectActuator, 1, act->data);
+ break;
+ case ACT_PROPERTY:
+ writestruct(wd, DATA, bPropertyActuator, 1, act->data);
+ break;
+ case ACT_CAMERA:
+ writestruct(wd, DATA, bCameraActuator, 1, act->data);
+ break;
+ case ACT_CONSTRAINT:
+ writestruct(wd, DATA, bConstraintActuator, 1, act->data);
+ break;
+ case ACT_EDIT_OBJECT:
+ writestruct(wd, DATA, bEditObjectActuator, 1, act->data);
+ break;
+ case ACT_SCENE:
+ writestruct(wd, DATA, bSceneActuator, 1, act->data);
+ break;
+ case ACT_GROUP:
+ writestruct(wd, DATA, bGroupActuator, 1, act->data);
+ break;
+ case ACT_RANDOM:
+ writestruct(wd, DATA, bRandomActuator, 1, act->data);
+ break;
+ case ACT_MESSAGE:
+ writestruct(wd, DATA, bMessageActuator, 1, act->data);
+ break;
+ case ACT_GAME:
+ writestruct(wd, DATA, bGameActuator, 1, act->data);
+ break;
+ case ACT_VISIBILITY:
+ writestruct(wd, DATA, bVisibilityActuator, 1, act->data);
+ break;
+ case ACT_2DFILTER:
+ writestruct(wd, DATA, bTwoDFilterActuator, 1, act->data);
+ break;
+ case ACT_PARENT:
+ writestruct(wd, DATA, bParentActuator, 1, act->data);
+ break;
+ case ACT_STATE:
+ writestruct(wd, DATA, bStateActuator, 1, act->data);
+ break;
+ case ACT_ARMATURE:
+ writestruct(wd, DATA, bArmatureActuator, 1, act->data);
+ break;
+ case ACT_STEERING:
+ writestruct(wd, DATA, bSteeringActuator, 1, act->data);
+ break;
+ case ACT_MOUSE:
+ writestruct(wd, DATA, bMouseActuator, 1, act->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- act= act->next;
+ act = act->next;
}
}
static void write_motionpath(WriteData *wd, bMotionPath *mpath)
{
/* sanity checks */
- if (mpath == NULL)
+ if (mpath == NULL) {
return;
-
+ }
+
/* firstly, just write the motionpath struct */
- writestruct(wd, DATA, "bMotionPath", 1, mpath);
-
+ writestruct(wd, DATA, bMotionPath, 1, mpath);
+
/* now write the array of data */
- writestruct(wd, DATA, "bMotionPathVert", mpath->length, mpath->points);
+ writestruct(wd, DATA, bMotionPathVert, mpath->length, mpath->points);
}
static void write_constraints(WriteData *wd, ListBase *conlist)
{
bConstraint *con;
- for (con=conlist->first; con; con=con->next) {
- const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
-
+ for (con = conlist->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
/* Write the specific data */
if (cti && con->data) {
/* firstly, just write the plain con->data struct */
- writestruct(wd, DATA, cti->structName, 1, con->data);
-
+ writestruct_id(wd, DATA, cti->structName, 1, con->data);
+
/* do any constraint specific stuff */
switch (con->type) {
case CONSTRAINT_TYPE_PYTHON:
{
- bPythonConstraint *data = (bPythonConstraint *)con->data;
+ bPythonConstraint *data = con->data;
bConstraintTarget *ct;
-
+
/* write targets */
- for (ct= data->targets.first; ct; ct= ct->next)
- writestruct(wd, DATA, "bConstraintTarget", 1, ct);
-
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ writestruct(wd, DATA, bConstraintTarget, 1, ct);
+ }
+
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
break;
}
- case CONSTRAINT_TYPE_SPLINEIK:
+ case CONSTRAINT_TYPE_SPLINEIK:
{
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-
+ bSplineIKConstraint *data = con->data;
+
/* write points array */
- writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points);
+ writedata(wd, DATA, sizeof(float) * (data->numpoints), data->points);
break;
}
}
}
-
+
/* Write the constraint */
- writestruct(wd, DATA, "bConstraint", 1, con);
+ writestruct(wd, DATA, bConstraint, 1, con);
}
}
@@ -1478,176 +1630,191 @@ static void write_pose(WriteData *wd, bPose *pose)
bActionGroup *grp;
/* Write each channel */
- if (!pose)
+ if (pose == NULL) {
return;
+ }
/* Write channels */
- for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ for (chan = pose->chanbase.first; chan; chan = chan->next) {
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (chan->prop)
+ if (chan->prop) {
IDP_WriteProperty(chan->prop, wd);
-
+ }
+
write_constraints(wd, &chan->constraints);
-
+
write_motionpath(wd, chan->mpath);
-
- /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */
- if (chan->bone)
- chan->selectflag= chan->bone->flag & BONE_SELECTED; /* gets restored on read, for library armatures */
-
- writestruct(wd, DATA, "bPoseChannel", 1, chan);
- }
-
+
+ /* prevent crashes with autosave,
+ * when a bone duplicated in editmode has not yet been assigned to its posechannel */
+ if (chan->bone) {
+ /* gets restored on read, for library armatures */
+ chan->selectflag = chan->bone->flag & BONE_SELECTED;
+ }
+
+ writestruct(wd, DATA, bPoseChannel, 1, chan);
+ }
+
/* Write groups */
- for (grp=pose->agroups.first; grp; grp=grp->next)
- writestruct(wd, DATA, "bActionGroup", 1, grp);
+ for (grp = pose->agroups.first; grp; grp = grp->next) {
+ writestruct(wd, DATA, bActionGroup, 1, grp);
+ }
/* write IK param */
if (pose->ikparam) {
const char *structname = BKE_pose_ikparam_get_name(pose);
- if (structname)
- writestruct(wd, DATA, structname, 1, pose->ikparam);
+ if (structname) {
+ writestruct_id(wd, DATA, structname, 1, pose->ikparam);
+ }
}
/* Write this pose */
- writestruct(wd, DATA, "bPose", 1, pose);
+ writestruct(wd, DATA, bPose, 1, pose);
}
static void write_defgroups(WriteData *wd, ListBase *defbase)
{
- bDeformGroup *defgroup;
-
- for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
- writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
+ for (bDeformGroup *defgroup = defbase->first; defgroup; defgroup = defgroup->next) {
+ writestruct(wd, DATA, bDeformGroup, 1, defgroup);
+ }
}
static void write_modifiers(WriteData *wd, ListBase *modbase)
{
ModifierData *md;
- if (modbase == NULL) return;
- for (md=modbase->first; md; md= md->next) {
+ if (modbase == NULL) {
+ return;
+ }
+
+ for (md = modbase->first; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti == NULL) return;
-
- writestruct(wd, DATA, mti->structName, 1, md);
-
- if (md->type==eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData*) md;
-
+ if (mti == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, mti->structName, 1, md);
+
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+
if (hmd->curfalloff) {
write_curvemapping(wd, hmd->curfalloff);
}
- writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
+ writedata(wd, DATA, sizeof(int) * hmd->totindex, hmd->indexar);
}
- else if (md->type==eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData*) md;
-
- writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms);
- writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms);
- writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights);
+ else if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms);
+ writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms);
+ writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights);
write_pointcaches(wd, &clmd->ptcaches);
}
- else if (md->type==eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData*) md;
-
+ else if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
if (smd->domain) {
write_pointcaches(wd, &(smd->domain->ptcaches[0]));
/* create fake pointcache so that old blender versions can read it */
smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE|PTCACHE_FAKE_SMOKE;
+ smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
smd->domain->point_cache[1]->step = 1;
write_pointcaches(wd, &(smd->domain->ptcaches[1]));
}
-
- writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain);
+
+ writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
if (smd->domain) {
/* cleanup the fake pointcache */
BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
smd->domain->point_cache[1] = NULL;
-
- writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights);
+
+ writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_FLOW)
- writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow);
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll);
+ else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
+ writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow);
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll);
+ }
}
- else if (md->type==eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData*) md;
-
- writestruct(wd, DATA, "FluidsimSettings", 1, fluidmd->fss);
+ else if (md->type == eModifierType_Fluidsim) {
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
+
+ writestruct(wd, DATA, FluidsimSettings, 1, fluidmd->fss);
}
- else if (md->type==eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData*) md;
-
+ else if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+
if (pmd->canvas) {
DynamicPaintSurface *surface;
- writestruct(wd, DATA, "DynamicPaintCanvasSettings", 1, pmd->canvas);
-
+ writestruct(wd, DATA, DynamicPaintCanvasSettings, 1, pmd->canvas);
+
/* write surfaces */
- for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next)
- writestruct(wd, DATA, "DynamicPaintSurface", 1, surface);
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ writestruct(wd, DATA, DynamicPaintSurface, 1, surface);
+ }
/* write caches and effector weights */
- for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) {
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
write_pointcaches(wd, &(surface->ptcaches));
- writestruct(wd, DATA, "EffectorWeights", 1, surface->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights);
}
}
if (pmd->brush) {
- writestruct(wd, DATA, "DynamicPaintBrushSettings", 1, pmd->brush);
- writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp);
- writestruct(wd, DATA, "ColorBand", 1, pmd->brush->vel_ramp);
+ writestruct(wd, DATA, DynamicPaintBrushSettings, 1, pmd->brush);
+ writestruct(wd, DATA, ColorBand, 1, pmd->brush->paint_ramp);
+ writestruct(wd, DATA, ColorBand, 1, pmd->brush->vel_ramp);
}
}
- else if (md->type==eModifierType_Collision) {
-
+ else if (md->type == eModifierType_Collision) {
+
#if 0
- CollisionModifierData *collmd = (CollisionModifierData*) md;
- // TODO: CollisionModifier should use pointcache
+ CollisionModifierData *collmd = (CollisionModifierData *)md;
+ // TODO: CollisionModifier should use pointcache
// + have proper reset events before enabling this
- writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x);
- writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew);
- writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces);
+ writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
+ writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
+ writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
#endif
}
- else if (md->type==eModifierType_MeshDeform) {
- MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+ else if (md->type == eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
int size = mmd->dyngridsize;
- writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences);
+ writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->bindinfluences);
writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets);
writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert,
- mmd->bindcagecos);
- writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid);
- writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences);
- writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts);
+ mmd->bindcagecos);
+ writestruct(wd, DATA, MDefCell, size * size * size, mmd->dyngrid);
+ writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->dyninfluences);
+ writedata(wd, DATA, sizeof(int) * mmd->totvert, mmd->dynverts);
}
- else if (md->type==eModifierType_Warp) {
- WarpModifierData *tmd = (WarpModifierData*) md;
+ else if (md->type == eModifierType_Warp) {
+ WarpModifierData *tmd = (WarpModifierData *)md;
if (tmd->curfalloff) {
write_curvemapping(wd, tmd->curfalloff);
}
}
- else if (md->type==eModifierType_WeightVGEdit) {
- WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ else if (md->type == eModifierType_WeightVGEdit) {
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
- if (wmd->cmap_curve)
+ if (wmd->cmap_curve) {
write_curvemapping(wd, wmd->cmap_curve);
+ }
}
- else if (md->type==eModifierType_LaplacianDeform) {
- LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData*) md;
+ else if (md->type == eModifierType_LaplacianDeform) {
+ LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
- writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
+ writedata(wd, DATA, sizeof(float) * lmd->total_verts * 3, lmd->vertexco);
}
else if (md->type == eModifierType_CorrectiveSmooth) {
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
@@ -1662,22 +1829,21 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
static void write_objects(WriteData *wd, ListBase *idbase)
{
Object *ob;
-
- ob= idbase->first;
+
+ ob = idbase->first;
while (ob) {
- if (ob->id.us>0 || wd->current) {
+ if (ob->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_OB, "Object", 1, ob);
-
- /* Write ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
-
- if (ob->adt) write_animdata(wd, ob->adt);
-
+ writestruct(wd, ID_OB, Object, 1, ob);
+ write_iddata(wd, &ob->id);
+
+ if (ob->adt) {
+ write_animdata(wd, ob->adt);
+ }
+
/* direct data */
- writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
- writedata(wd, DATA, sizeof(char)*ob->totcol, ob->matbits);
+ writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat);
+ writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits);
/* write_effects(wd, &ob->effect); */ /* not used anymore */
write_properties(wd, &ob->prop);
write_sensors(wd, &ob->sensors);
@@ -1695,37 +1861,37 @@ static void write_objects(WriteData *wd, ListBase *idbase)
write_defgroups(wd, &ob->defbase);
write_constraints(wd, &ob->constraints);
write_motionpath(wd, ob->mpath);
-
- writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
- writestruct(wd, DATA, "SoftBody", 1, ob->soft);
+
+ writestruct(wd, DATA, PartDeflect, 1, ob->pd);
+ writestruct(wd, DATA, SoftBody, 1, ob->soft);
if (ob->soft) {
write_pointcaches(wd, &ob->soft->ptcaches);
- writestruct(wd, DATA, "EffectorWeights", 1, ob->soft->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
}
- writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
-
+ writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
+
if (ob->rigidbody_object) {
- // TODO: if any extra data is added to handle duplis, will need separate function then
- writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object);
+ /* TODO: if any extra data is added to handle duplis, will need separate function then */
+ writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object);
}
if (ob->rigidbody_constraint) {
- writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint);
+ writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
}
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- writestruct(wd, DATA, "ImageUser", 1, ob->iuser);
+ writestruct(wd, DATA, ImageUser, 1, ob->iuser);
}
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
- writelist(wd, DATA, "LinkData", &ob->pc_ids);
- writelist(wd, DATA, "LodLevel", &ob->lodlevels);
+ writelist(wd, DATA, LinkData, &ob->pc_ids);
+ writelist(wd, DATA, LodLevel, &ob->lodlevels);
}
write_previews(wd, ob->preview);
- ob= ob->id.next;
+ ob = ob->id.next;
}
/* flush helps the compression for undo-save */
@@ -1736,25 +1902,25 @@ static void write_objects(WriteData *wd, ListBase *idbase)
static void write_vfonts(WriteData *wd, ListBase *idbase)
{
VFont *vf;
- PackedFile * pf;
+ PackedFile *pf;
- vf= idbase->first;
+ vf = idbase->first;
while (vf) {
- if (vf->id.us>0 || wd->current) {
+ if (vf->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_VF, "VFont", 1, vf);
- if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd);
+ writestruct(wd, ID_VF, VFont, 1, vf);
+ write_iddata(wd, &vf->id);
/* direct data */
if (vf->packedfile) {
pf = vf->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
- vf= vf->id.next;
+ vf = vf->id.next;
}
}
@@ -1764,25 +1930,29 @@ static void write_keys(WriteData *wd, ListBase *idbase)
Key *key;
KeyBlock *kb;
- key= idbase->first;
+ key = idbase->first;
while (key) {
- if (key->id.us>0 || wd->current) {
+ if (key->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_KE, "Key", 1, key);
- if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
-
- if (key->adt) write_animdata(wd, key->adt);
-
+ writestruct(wd, ID_KE, Key, 1, key);
+ write_iddata(wd, &key->id);
+
+ if (key->adt) {
+ write_animdata(wd, key->adt);
+ }
+
/* direct data */
- kb= key->block.first;
+ kb = key->block.first;
while (kb) {
- writestruct(wd, DATA, "KeyBlock", 1, kb);
- if (kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
- kb= kb->next;
+ writestruct(wd, DATA, KeyBlock, 1, kb);
+ if (kb->data) {
+ writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
+ }
+ kb = kb->next;
}
}
- key= key->id.next;
+ key = key->id.next;
}
/* flush helps the compression for undo-save */
mywrite(wd, MYWRITE_FLUSH, 0);
@@ -1792,17 +1962,19 @@ static void write_cameras(WriteData *wd, ListBase *idbase)
{
Camera *cam;
- cam= idbase->first;
+ cam = idbase->first;
while (cam) {
- if (cam->id.us>0 || wd->current) {
+ if (cam->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_CA, "Camera", 1, cam);
- if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd);
-
- if (cam->adt) write_animdata(wd, cam->adt);
+ writestruct(wd, ID_CA, Camera, 1, cam);
+ write_iddata(wd, &cam->id);
+
+ if (cam->adt) {
+ write_animdata(wd, cam->adt);
+ }
}
- cam= cam->id.next;
+ cam = cam->id.next;
}
}
@@ -1811,24 +1983,26 @@ static void write_mballs(WriteData *wd, ListBase *idbase)
MetaBall *mb;
MetaElem *ml;
- mb= idbase->first;
+ mb = idbase->first;
while (mb) {
- if (mb->id.us>0 || wd->current) {
+ if (mb->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_MB, "MetaBall", 1, mb);
- if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd);
+ writestruct(wd, ID_MB, MetaBall, 1, mb);
+ write_iddata(wd, &mb->id);
/* direct data */
- writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
- if (mb->adt) write_animdata(wd, mb->adt);
+ writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat);
+ if (mb->adt) {
+ write_animdata(wd, mb->adt);
+ }
- ml= mb->elems.first;
+ ml = mb->elems.first;
while (ml) {
- writestruct(wd, DATA, "MetaElem", 1, ml);
- ml= ml->next;
+ writestruct(wd, DATA, MetaElem, 1, ml);
+ ml = ml->next;
}
}
- mb= mb->id.next;
+ mb = mb->id.next;
}
}
@@ -1837,43 +2011,50 @@ static void write_curves(WriteData *wd, ListBase *idbase)
Curve *cu;
Nurb *nu;
- cu= idbase->first;
+ cu = idbase->first;
while (cu) {
- if (cu->id.us>0 || wd->current) {
+ if (cu->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_CU, "Curve", 1, cu);
-
+ writestruct(wd, ID_CU, Curve, 1, cu);
+ write_iddata(wd, &cu->id);
+
/* direct data */
- writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
- if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd);
- if (cu->adt) write_animdata(wd, cu->adt);
-
+ writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat);
+ if (cu->adt) {
+ write_animdata(wd, cu->adt);
+ }
+
if (cu->vfont) {
writedata(wd, DATA, cu->len + 1, cu->str);
- writestruct(wd, DATA, "CharInfo", cu->len_wchar + 1, cu->strinfo);
- writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
+ writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo);
+ writestruct(wd, DATA, TextBox, cu->totbox, cu->tb);
}
else {
/* is also the order of reading */
- nu= cu->nurb.first;
+ nu = cu->nurb.first;
while (nu) {
- writestruct(wd, DATA, "Nurb", 1, nu);
- nu= nu->next;
+ writestruct(wd, DATA, Nurb, 1, nu);
+ nu = nu->next;
}
- nu= cu->nurb.first;
+ nu = cu->nurb.first;
while (nu) {
- if (nu->type == CU_BEZIER)
- writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
+ if (nu->type == CU_BEZIER) {
+ writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
+ }
else {
- writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
- if (nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
- if (nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
+ writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp);
+ if (nu->knotsu) {
+ writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu);
+ }
+ if (nu->knotsv) {
+ writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv);
+ }
}
- nu= nu->next;
+ nu = nu->next;
}
}
}
- cu= cu->id.next;
+ cu = cu->id.next;
}
/* flush helps the compression for undo-save */
@@ -1883,15 +2064,15 @@ static void write_curves(WriteData *wd, ListBase *idbase)
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
{
if (dvlist) {
- int i;
-
+
/* Write the dvert list */
- writestruct(wd, DATA, "MDeformVert", count, dvlist);
-
+ writestruct(wd, DATA, MDeformVert, count, dvlist);
+
/* Write deformation data for each dvert */
- for (i=0; i<count; i++) {
- if (dvlist[i].dw)
- writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
+ for (int i = 0; i < count; i++) {
+ if (dvlist[i].dw) {
+ writestruct(wd, DATA, MDeformWeight, dvlist[i].totweight, dvlist[i].dw);
+ }
}
}
}
@@ -1900,17 +2081,19 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
{
if (mdlist) {
int i;
-
- writestruct(wd, DATA, "MDisps", count, mdlist);
+
+ writestruct(wd, DATA, MDisps, count, mdlist);
for (i = 0; i < count; ++i) {
MDisps *md = &mdlist[i];
if (md->disps) {
- if (!external)
+ if (!external) {
writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps);
+ }
}
-
- if (md->hidden)
+
+ if (md->hidden) {
writedata(wd, DATA, BLI_BITMAP_SIZE(md->totdisp), md->hidden);
+ }
}
}
}
@@ -1919,8 +2102,8 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
{
if (grid_paint_mask) {
int i;
-
- writestruct(wd, DATA, "GridPaintMask", count, grid_paint_mask);
+
+ writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask);
for (i = 0; i < count; ++i) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
@@ -1940,11 +2123,12 @@ static void write_customdata(
int i;
/* write external customdata (not for undo) */
- if (data->external && !wd->current)
+ if (data->external && !wd->current) {
CustomData_external_write(data, id, CD_MASK_MESH, count, 0);
+ }
+
+ writestruct_at_address(wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers);
- writestruct_at_address(wd, DATA, "CustomDataLayer", data->totlayer, data->layers, layers);
-
for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &layers[i];
const char *structname;
@@ -1970,10 +2154,14 @@ static void write_customdata(
/* when using partial visibility, the MEdge and MFace layers
* are smaller than the original, so their type and count is
* passed to make this work */
- if (layer->type != partial_type) datasize= structnum*count;
- else datasize= structnum*partial_count;
+ if (layer->type != partial_type) {
+ datasize = structnum * count;
+ }
+ else {
+ datasize = structnum * partial_count;
+ }
- writestruct(wd, DATA, structname, datasize, layer->data);
+ writestruct_id(wd, DATA, structname, datasize, layer->data);
}
else {
printf("%s error: layer '%s':%d - can't be written to file\n",
@@ -1982,20 +2170,21 @@ static void write_customdata(
}
}
- if (data->external)
- writestruct(wd, DATA, "CustomDataExternal", 1, data->external);
+ if (data->external) {
+ writestruct(wd, DATA, CustomDataExternal, 1, data->external);
+ }
}
static void write_meshes(WriteData *wd, ListBase *idbase)
{
Mesh *mesh;
- int save_for_old_blender= 0;
+ bool save_for_old_blender = false;
#ifdef USE_BMESH_SAVE_AS_COMPAT
save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
#endif
- mesh= idbase->first;
+ mesh = idbase->first;
while (mesh) {
CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
@@ -2003,7 +2192,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- if (mesh->id.us>0 || wd->current) {
+ if (mesh->id.us > 0 || wd->current) {
/* write LibData */
if (!save_for_old_blender) {
/* write a copy of the mesh, don't modify in place because it is
@@ -2036,13 +2225,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
- writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
/* direct data */
- if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
- if (mesh->adt) write_animdata(wd, mesh->adt);
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
@@ -2094,13 +2285,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
#endif
- writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
/* direct data */
- if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
- if (mesh->adt) write_animdata(wd, mesh->adt);
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
/* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
@@ -2137,44 +2330,46 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
MEM_freeN(players);
}
- mesh= mesh->id.next;
+ mesh = mesh->id.next;
}
}
static void write_lattices(WriteData *wd, ListBase *idbase)
{
Lattice *lt;
-
- lt= idbase->first;
+
+ lt = idbase->first;
while (lt) {
- if (lt->id.us>0 || wd->current) {
+ if (lt->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_LT, "Lattice", 1, lt);
- if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd);
-
+ writestruct(wd, ID_LT, Lattice, 1, lt);
+ write_iddata(wd, &lt->id);
+
/* write animdata */
- if (lt->adt) write_animdata(wd, lt->adt);
-
+ if (lt->adt) {
+ write_animdata(wd, lt->adt);
+ }
+
/* direct data */
- writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
-
- write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
-
+ writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
+
+ write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
+
}
- lt= lt->id.next;
+ lt = lt->id.next;
}
}
static void write_images(WriteData *wd, ListBase *idbase)
{
Image *ima;
- PackedFile * pf;
+ PackedFile *pf;
ImageView *iv;
ImagePackedFile *imapf;
- ima= idbase->first;
+ ima = idbase->first;
while (ima) {
- if (ima->id.us>0 || wd->current) {
+ if (ima->id.us > 0 || wd->current) {
/* Some trickery to keep forward compatibility of packed images. */
BLI_assert(ima->packedfile == NULL);
if (ima->packedfiles.first != NULL) {
@@ -2183,27 +2378,28 @@ static void write_images(WriteData *wd, ListBase *idbase)
}
/* write LibData */
- writestruct(wd, ID_IM, "Image", 1, ima);
- if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
+ writestruct(wd, ID_IM, Image, 1, ima);
+ write_iddata(wd, &ima->id);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
- writestruct(wd, DATA, "ImagePackedFile", 1, imapf);
+ writestruct(wd, DATA, ImagePackedFile, 1, imapf);
if (imapf->packedfile) {
pf = imapf->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
write_previews(wd, ima->preview);
- for (iv = ima->views.first; iv; iv = iv->next)
- writestruct(wd, DATA, "ImageView", 1, iv);
- writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format);
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ writestruct(wd, DATA, ImageView, 1, iv);
+ }
+ writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
ima->packedfile = NULL;
}
- ima= ima->id.next;
+ ima = ima->id.next;
}
/* flush helps the compression for undo-save */
mywrite(wd, MYWRITE_FLUSH, 0);
@@ -2213,35 +2409,49 @@ static void write_textures(WriteData *wd, ListBase *idbase)
{
Tex *tex;
- tex= idbase->first;
+ tex = idbase->first;
while (tex) {
- if (tex->id.us>0 || wd->current) {
+ if (tex->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_TE, "Tex", 1, tex);
- if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd);
+ writestruct(wd, ID_TE, Tex, 1, tex);
+ write_iddata(wd, &tex->id);
- if (tex->adt) write_animdata(wd, tex->adt);
+ if (tex->adt) {
+ write_animdata(wd, tex->adt);
+ }
/* direct data */
- if (tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
- if (tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
+ if (tex->coba) {
+ writestruct(wd, DATA, ColorBand, 1, tex->coba);
+ }
+ if (tex->type == TEX_ENVMAP && tex->env) {
+ writestruct(wd, DATA, EnvMap, 1, tex->env);
+ }
if (tex->type == TEX_POINTDENSITY && tex->pd) {
- writestruct(wd, DATA, "PointDensity", 1, tex->pd);
- if (tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba);
- if (tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve);
+ writestruct(wd, DATA, PointDensity, 1, tex->pd);
+ if (tex->pd->coba) {
+ writestruct(wd, DATA, ColorBand, 1, tex->pd->coba);
+ }
+ if (tex->pd->falloff_curve) {
+ write_curvemapping(wd, tex->pd->falloff_curve);
+ }
}
- if (tex->type == TEX_VOXELDATA) writestruct(wd, DATA, "VoxelData", 1, tex->vd);
- if (tex->type == TEX_OCEAN && tex->ot) writestruct(wd, DATA, "OceanTex", 1, tex->ot);
-
+ if (tex->type == TEX_VOXELDATA) {
+ writestruct(wd, DATA, VoxelData, 1, tex->vd);
+ }
+ if (tex->type == TEX_OCEAN && tex->ot) {
+ writestruct(wd, DATA, OceanTex, 1, tex->ot);
+ }
+
/* nodetree is integral part of texture, no libdata */
if (tex->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, tex->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
write_nodetree(wd, tex->nodetree);
}
-
+
write_previews(wd, tex->preview);
}
- tex= tex->id.next;
+ tex = tex->id.next;
}
/* flush helps the compression for undo-save */
@@ -2253,36 +2463,39 @@ static void write_materials(WriteData *wd, ListBase *idbase)
Material *ma;
int a;
- ma= idbase->first;
+ ma = idbase->first;
while (ma) {
- if (ma->id.us>0 || wd->current) {
+ if (ma->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_MA, "Material", 1, ma);
-
- /* Write ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- /* manually set head group property to IDP_GROUP, just in case it hadn't been
- * set yet :) */
- if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
-
- if (ma->adt) write_animdata(wd, ma->adt);
-
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
- }
-
- if (ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
- if (ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
-
+ writestruct(wd, ID_MA, Material, 1, ma);
+ write_iddata(wd, &ma->id);
+
+ if (ma->adt) {
+ write_animdata(wd, ma->adt);
+ }
+
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
+ }
+ }
+
+ if (ma->ramp_col) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
+ }
+ if (ma->ramp_spec) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ }
+
/* nodetree is integral part of material, no libdata */
if (ma->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
write_nodetree(wd, ma->nodetree);
}
write_previews(wd, ma->preview);
}
- ma= ma->id.next;
+ ma = ma->id.next;
}
}
@@ -2291,28 +2504,32 @@ static void write_worlds(WriteData *wd, ListBase *idbase)
World *wrld;
int a;
- wrld= idbase->first;
+ wrld = idbase->first;
while (wrld) {
- if (wrld->id.us>0 || wd->current) {
+ if (wrld->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_WO, "World", 1, wrld);
- if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd);
-
- if (wrld->adt) write_animdata(wd, wrld->adt);
-
- for (a=0; a<MAX_MTEX; a++) {
- if (wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
+ writestruct(wd, ID_WO, World, 1, wrld);
+ write_iddata(wd, &wrld->id);
+
+ if (wrld->adt) {
+ write_animdata(wd, wrld->adt);
+ }
+
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (wrld->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
+ }
}
/* nodetree is integral part of world, no libdata */
if (wrld->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, wrld->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
write_nodetree(wd, wrld->nodetree);
}
-
+
write_previews(wd, wrld->preview);
}
- wrld= wrld->id.next;
+ wrld = wrld->id.next;
}
}
@@ -2321,33 +2538,38 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
Lamp *la;
int a;
- la= idbase->first;
+ la = idbase->first;
while (la) {
- if (la->id.us>0 || wd->current) {
+ if (la->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_LA, "Lamp", 1, la);
- if (la->id.properties) IDP_WriteProperty(la->id.properties, wd);
-
- if (la->adt) write_animdata(wd, la->adt);
-
+ writestruct(wd, ID_LA, Lamp, 1, la);
+ write_iddata(wd, &la->id);
+
+ if (la->adt) {
+ write_animdata(wd, la->adt);
+ }
+
/* direct data */
- for (a=0; a<MAX_MTEX; a++) {
- if (la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (la->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, la->mtex[a]);
+ }
}
-
- if (la->curfalloff)
+
+ if (la->curfalloff) {
write_curvemapping(wd, la->curfalloff);
-
+ }
+
/* nodetree is integral part of lamps, no libdata */
if (la->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, la->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, la->nodetree);
write_nodetree(wd, la->nodetree);
}
write_previews(wd, la->preview);
-
+
}
- la= la->id.next;
+ la = la->id.next;
}
}
@@ -2359,21 +2581,21 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti) {
- writestruct(wd, DATA, smti->struct_name, 1, smd);
+ writestruct_id(wd, DATA, smti->struct_name, 1, smd);
if (smd->type == seqModifierType_Curves) {
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
write_curvemapping(wd, &cmd->curve_mapping);
}
else if (smd->type == seqModifierType_HueCorrect) {
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
write_curvemapping(wd, &hcmd->curve_mapping);
}
}
else {
- writestruct(wd, DATA, "SequenceModifierData", 1, smd);
+ writestruct(wd, DATA, SequenceModifierData, 1, smd);
}
}
}
@@ -2387,8 +2609,9 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se
static void write_paint(WriteData *wd, Paint *p)
{
- if (p->cavity_curve)
+ if (p->cavity_curve) {
write_curvemapping(wd, p->cavity_curve);
+ }
}
static void write_scenes(WriteData *wd, ListBase *scebase)
@@ -2406,106 +2629,114 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
ToolSettings *tos;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
-
- sce= scebase->first;
+
+ sce = scebase->first;
while (sce) {
/* write LibData */
- writestruct(wd, ID_SCE, "Scene", 1, sce);
- if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd);
-
- if (sce->adt) write_animdata(wd, sce->adt);
+ writestruct(wd, ID_SCE, Scene, 1, sce);
+ write_iddata(wd, &sce->id);
+
+ if (sce->adt) {
+ write_animdata(wd, sce->adt);
+ }
write_keyingsets(wd, &sce->keyingsets);
-
+
/* direct data */
- base= sce->base.first;
+ base = sce->base.first;
while (base) {
- writestruct(wd, DATA, "Base", 1, base);
- base= base->next;
+ writestruct(wd, DATA, Base, 1, base);
+ base = base->next;
}
-
+
tos = sce->toolsettings;
- writestruct(wd, DATA, "ToolSettings", 1, tos);
+ writestruct(wd, DATA, ToolSettings, 1, tos);
if (tos->vpaint) {
- writestruct(wd, DATA, "VPaint", 1, tos->vpaint);
- write_paint (wd, &tos->vpaint->paint);
+ writestruct(wd, DATA, VPaint, 1, tos->vpaint);
+ write_paint(wd, &tos->vpaint->paint);
}
if (tos->wpaint) {
- writestruct(wd, DATA, "VPaint", 1, tos->wpaint);
- write_paint (wd, &tos->wpaint->paint);
+ writestruct(wd, DATA, VPaint, 1, tos->wpaint);
+ write_paint(wd, &tos->wpaint->paint);
}
if (tos->sculpt) {
- writestruct(wd, DATA, "Sculpt", 1, tos->sculpt);
- write_paint (wd, &tos->sculpt->paint);
+ writestruct(wd, DATA, Sculpt, 1, tos->sculpt);
+ write_paint(wd, &tos->sculpt->paint);
}
if (tos->uvsculpt) {
- writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt);
- write_paint (wd, &tos->uvsculpt->paint);
+ writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
+ write_paint(wd, &tos->uvsculpt->paint);
}
write_paint(wd, &tos->imapaint.paint);
- ed= sce->ed;
+ ed = sce->ed;
if (ed) {
- writestruct(wd, DATA, "Editing", 1, ed);
-
+ writestruct(wd, DATA, Editing, 1, ed);
+
/* reset write flags too */
-
- SEQ_BEGIN (ed, seq)
+
+ SEQ_BEGIN(ed, seq)
{
- if (seq->strip) seq->strip->done = false;
- writestruct(wd, DATA, "Sequence", 1, seq);
+ if (seq->strip) {
+ seq->strip->done = false;
+ }
+ writestruct(wd, DATA, Sequence, 1, seq);
}
SEQ_END
-
- SEQ_BEGIN (ed, seq)
+
+ SEQ_BEGIN(ed, seq)
{
- if (seq->strip && seq->strip->done==0) {
+ if (seq->strip && seq->strip->done == 0) {
/* write strip with 'done' at 0 because readfile */
-
+
if (seq->effectdata) {
switch (seq->type) {
- case SEQ_TYPE_COLOR:
- writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_SPEED:
- writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_WIPE:
- writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_GLOW:
- writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_TRANSFORM:
- writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_GAUSSIAN_BLUR:
- writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_TEXT:
- writestruct(wd, DATA, "TextVars", 1, seq->effectdata);
- break;
+ case SEQ_TYPE_COLOR:
+ writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_SPEED:
+ writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_WIPE:
+ writestruct(wd, DATA, WipeVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GLOW:
+ writestruct(wd, DATA, GlowVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TRANSFORM:
+ writestruct(wd, DATA, TransformVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TEXT:
+ writestruct(wd, DATA, TextVars, 1, seq->effectdata);
+ break;
}
}
- writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format);
+ writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
- strip= seq->strip;
- writestruct(wd, DATA, "Strip", 1, strip);
+ strip = seq->strip;
+ writestruct(wd, DATA, Strip, 1, strip);
if (seq->flag & SEQ_USE_CROP && strip->crop) {
- writestruct(wd, DATA, "StripCrop", 1, strip->crop);
+ writestruct(wd, DATA, StripCrop, 1, strip->crop);
}
if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
- writestruct(wd, DATA, "StripTransform", 1, strip->transform);
+ writestruct(wd, DATA, StripTransform, 1, strip->transform);
}
if (seq->flag & SEQ_USE_PROXY && strip->proxy) {
- writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
+ writestruct(wd, DATA, StripProxy, 1, strip->proxy);
}
- if (seq->type==SEQ_TYPE_IMAGE)
- writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata);
- else if (seq->type==SEQ_TYPE_MOVIE || seq->type==SEQ_TYPE_SOUND_RAM || seq->type == SEQ_TYPE_SOUND_HD)
- writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
-
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ writestruct(wd, DATA, StripElem,
+ MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
+ strip->stripdata);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ writestruct(wd, DATA, StripElem, 1, strip->stripdata);
+ }
+
strip->done = true;
}
@@ -2516,67 +2747,76 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
write_sequence_modifiers(wd, &seq->modifiers);
}
SEQ_END
-
+
/* new; meta stack too, even when its nasty restore code */
- for (ms= ed->metastack.first; ms; ms= ms->next) {
- writestruct(wd, DATA, "MetaStack", 1, ms);
+ for (ms = ed->metastack.first; ms; ms = ms->next) {
+ writestruct(wd, DATA, MetaStack, 1, ms);
}
}
-
+
if (sce->r.avicodecdata) {
- writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
- if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
- if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata);
+ if (sce->r.avicodecdata->lpFormat) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
+ }
+ if (sce->r.avicodecdata->lpParms) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ }
}
if (sce->r.qtcodecdata) {
- writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
- if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata->cdParms) {
+ writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ }
}
if (sce->r.ffcodecdata.properties) {
IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
}
/* writing dynamic list of TimeMarkers to the blend file */
- for (marker= sce->markers.first; marker; marker= marker->next)
- writestruct(wd, DATA, "TimeMarker", 1, marker);
-
+ for (marker = sce->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
+ }
+
/* writing dynamic list of TransformOrientations to the blend file */
- for (ts = sce->transform_spaces.first; ts; ts = ts->next)
- writestruct(wd, DATA, "TransformOrientation", 1, ts);
-
+ for (ts = sce->transform_spaces.first; ts; ts = ts->next) {
+ writestruct(wd, DATA, TransformOrientation, 1, ts);
+ }
+
for (srl = sce->r.layers.first; srl; srl = srl->next) {
- writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+ writestruct(wd, DATA, SceneRenderLayer, 1, srl);
for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc);
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
}
for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
}
}
/* writing MultiView to the blend file */
- for (srv = sce->r.views.first; srv; srv = srv->next)
- writestruct(wd, DATA, "SceneRenderView", 1, srv);
-
+ for (srv = sce->r.views.first; srv; srv = srv->next) {
+ writestruct(wd, DATA, SceneRenderView, 1, srv);
+ }
+
if (sce->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
write_nodetree(wd, sce->nodetree);
}
write_view_settings(wd, &sce->view_settings);
-
+
/* writing RigidBodyWorld data to the blend file */
if (sce->rigidbody_world) {
- writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
- writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
+ writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
+ writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
-
+
write_previews(wd, sce->preview);
write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
- sce= sce->id.next;
+ sce = sce->id.next;
}
/* flush helps the compression for undo-save */
mywrite(wd, MYWRITE_FLUSH, 0);
@@ -2588,26 +2828,29 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
- for (gpd= lb->first; gpd; gpd= gpd->id.next) {
- if (gpd->id.us>0 || wd->current) {
+
+ for (gpd = lb->first; gpd; gpd = gpd->id.next) {
+ if (gpd->id.us > 0 || wd->current) {
/* write gpd data block to file */
- writestruct(wd, ID_GD, "bGPdata", 1, gpd);
-
- if (gpd->adt) write_animdata(wd, gpd->adt);
-
+ writestruct(wd, ID_GD, bGPdata, 1, gpd);
+ write_iddata(wd, &gpd->id);
+
+ if (gpd->adt) {
+ write_animdata(wd, gpd->adt);
+ }
+
/* write grease-pencil layers to file */
- writelist(wd, DATA, "bGPDlayer", &gpd->layers);
- for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
-
+ writelist(wd, DATA, bGPDlayer, &gpd->layers);
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+
/* write this layer's frames to file */
- writelist(wd, DATA, "bGPDframe", &gpl->frames);
- for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
-
+ writelist(wd, DATA, bGPDframe, &gpl->frames);
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+
/* write strokes */
- writelist(wd, DATA, "bGPDstroke", &gpf->strokes);
- for (gps= gpf->strokes.first; gps; gps= gps->next) {
- writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);
+ writelist(wd, DATA, bGPDstroke, &gpf->strokes);
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
}
}
}
@@ -2619,32 +2862,35 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb)
{
wmWindowManager *wm;
wmWindow *win;
-
- for (wm= lb->first; wm; wm= wm->id.next) {
- writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
-
- for (win= wm->windows.first; win; win= win->next) {
- writestruct(wd, DATA, "wmWindow", 1, win);
- writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format);
+
+ for (wm = lb->first; wm; wm = wm->id.next) {
+ writestruct(wd, ID_WM, wmWindowManager, 1, wm);
+ write_iddata(wd, &wm->id);
+
+ for (win = wm->windows.first; win; win = win->next) {
+ writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
}
}
}
static void write_region(WriteData *wd, ARegion *ar, int spacetype)
-{
- writestruct(wd, DATA, "ARegion", 1, ar);
-
+{
+ writestruct(wd, DATA, ARegion, 1, ar);
+
if (ar->regiondata) {
switch (spacetype) {
case SPACE_VIEW3D:
- if (ar->regiontype==RGN_TYPE_WINDOW) {
- RegionView3D *rv3d= ar->regiondata;
- writestruct(wd, DATA, "RegionView3D", 1, rv3d);
-
- if (rv3d->localvd)
- writestruct(wd, DATA, "RegionView3D", 1, rv3d->localvd);
- if (rv3d->clipbb)
- writestruct(wd, DATA, "BoundBox", 1, rv3d->clipbb);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ writestruct(wd, DATA, RegionView3D, 1, rv3d);
+
+ if (rv3d->localvd) {
+ writestruct(wd, DATA, RegionView3D, 1, rv3d->localvd);
+ }
+ if (rv3d->clipbb) {
+ writestruct(wd, DATA, BoundBox, 1, rv3d->clipbb);
+ }
}
else
@@ -2658,7 +2904,7 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype)
static void write_uilist(WriteData *wd, uiList *ui_list)
{
- writestruct(wd, DATA, "uiList", 1, ui_list);
+ writestruct(wd, DATA, uiList, 1, ui_list);
if (ui_list->properties) {
IDP_WriteProperty(ui_list->properties, wd);
@@ -2668,7 +2914,7 @@ static void write_uilist(WriteData *wd, uiList *ui_list)
static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list)
{
BLI_mempool *ts = so->treestore;
-
+
if (ts) {
int elems = BLI_mempool_count(ts);
/* linearize mempool to array */
@@ -2680,13 +2926,13 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list)
ts_flat->usedelem = elems;
ts_flat->totelem = elems;
ts_flat->data = data;
-
+
/* temporarily replace mempool-treestore by flat-treestore */
so->treestore = (BLI_mempool *)ts_flat;
- writestruct(wd, DATA, "SpaceOops", 1, so);
+ writestruct(wd, DATA, SpaceOops, 1, so);
- writestruct(wd, DATA, "TreeStore", 1, ts_flat);
- writestruct(wd, DATA, "TreeStoreElem", elems, data);
+ writestruct(wd, DATA, TreeStore, 1, ts_flat);
+ writestruct(wd, DATA, TreeStoreElem, elems, 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
@@ -2697,14 +2943,14 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list)
}
else {
so->treestore = NULL;
- writestruct(wd, DATA, "SpaceOops", 1, so);
+ writestruct(wd, DATA, SpaceOops, 1, so);
}
/* restore old treestore */
so->treestore = ts;
}
else {
- writestruct(wd, DATA, "SpaceOops", 1, so);
+ writestruct(wd, DATA, SpaceOops, 1, so);
}
}
@@ -2716,277 +2962,236 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
ScrEdge *se;
LinkNode *tmp_mem_list = NULL;
- sc= scrbase->first;
+ sc = scrbase->first;
while (sc) {
-
+
/* write LibData */
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
- writestruct(wd, ID_SCRN, "Screen", 1, sc);
- if (sc->id.properties)
- IDP_WriteProperty(sc->id.properties, wd);
-
+ writestruct(wd, ID_SCRN, bScreen, 1, sc);
+ write_iddata(wd, &sc->id);
+
/* direct data */
- for (sv= sc->vertbase.first; sv; sv= sv->next)
- writestruct(wd, DATA, "ScrVert", 1, sv);
-
- for (se= sc->edgebase.first; se; se= se->next)
- writestruct(wd, DATA, "ScrEdge", 1, se);
-
- for (sa= sc->areabase.first; sa; sa= sa->next) {
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ writestruct(wd, DATA, ScrVert, 1, sv);
+ }
+
+ for (se = sc->edgebase.first; se; se = se->next) {
+ writestruct(wd, DATA, ScrEdge, 1, se);
+ }
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
Panel *pa;
uiList *ui_list;
uiPreview *ui_preview;
PanelCategoryStack *pc_act;
ARegion *ar;
-
- writestruct(wd, DATA, "ScrArea", 1, sa);
-
- for (ar= sa->regionbase.first; ar; ar= ar->next) {
+
+ writestruct(wd, DATA, ScrArea, 1, sa);
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
write_region(wd, ar, sa->spacetype);
-
- for (pa= ar->panels.first; pa; pa= pa->next)
- writestruct(wd, DATA, "Panel", 1, pa);
-
- for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next)
- writestruct(wd, DATA, "PanelCategoryStack", 1, pc_act);
-
- for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next)
+
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ writestruct(wd, DATA, Panel, 1, pa);
+ }
+
+ for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) {
+ writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
+ }
+
+ for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
write_uilist(wd, ui_list);
+ }
- for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next)
- writestruct(wd, DATA, "uiPreview", 1, ui_preview);
+ for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
+ writestruct(wd, DATA, uiPreview, 1, ui_preview);
+ }
}
-
- sl= sa->spacedata.first;
+
+ sl = sa->spacedata.first;
while (sl) {
- for (ar= sl->regionbase.first; ar; ar= ar->next)
+ for (ar = sl->regionbase.first; ar; ar = ar->next) {
write_region(wd, ar, sl->spacetype);
-
- if (sl->spacetype==SPACE_VIEW3D) {
- View3D *v3d= (View3D *) sl;
+ }
+
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
BGpic *bgpic;
- writestruct(wd, DATA, "View3D", 1, v3d);
- for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
- writestruct(wd, DATA, "BGpic", 1, bgpic);
- if (v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
-
- if (v3d->fx_settings.ssao)
- writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->fx_settings.ssao);
- if (v3d->fx_settings.dof)
- writestruct(wd, DATA, "GPUDOFSettings", 1, v3d->fx_settings.dof);
-
- if (v3d->pbr_settings.brdf)
- writestruct(wd, DATA, "GPUBRDFSettings", 1, v3d->pbr_settings.brdf);
+ writestruct(wd, DATA, View3D, 1, v3d);
+ for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ writestruct(wd, DATA, BGpic, 1, bgpic);
+ }
+ if (v3d->localvd) {
+ writestruct(wd, DATA, View3D, 1, v3d->localvd);
+ }
+
+ if (v3d->fx_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
+ }
+ if (v3d->fx_settings.dof) {
+ writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
+ }
+
+ if (v3d->pbr_settings.brdf) {
+ writestruct(wd, DATA, GPUBRDFSettings, 1, v3d->pbr_settings.brdf);
+ }
if (v3d->pbr_settings.ssr)
- writestruct(wd, DATA, "GPUSSRSettings", 1, v3d->pbr_settings.ssr);
- if (v3d->pbr_settings.ssao)
- writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->pbr_settings.ssao);
+ {
+ writestruct(wd, DATA, GPUSSRSettings, 1, v3d->pbr_settings.ssr);
+ }
+ if (v3d->pbr_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->pbr_settings.ssao);
+ }
}
- else if (sl->spacetype==SPACE_IPO) {
- SpaceIpo *sipo= (SpaceIpo *)sl;
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
ListBase tmpGhosts = sipo->ghostCurves;
-
+
/* temporarily disable ghost curves when saving */
- sipo->ghostCurves.first= sipo->ghostCurves.last= NULL;
-
- writestruct(wd, DATA, "SpaceIpo", 1, sl);
- if (sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads);
-
+ sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
+
+ writestruct(wd, DATA, SpaceIpo, 1, sl);
+ if (sipo->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
+ }
+
/* reenable ghost curves */
- sipo->ghostCurves= tmpGhosts;
+ sipo->ghostCurves = tmpGhosts;
}
- else if (sl->spacetype==SPACE_BUTS) {
- writestruct(wd, DATA, "SpaceButs", 1, sl);
+ else if (sl->spacetype == SPACE_BUTS) {
+ writestruct(wd, DATA, SpaceButs, 1, sl);
}
- else if (sl->spacetype==SPACE_FILE) {
- SpaceFile *sfile= (SpaceFile *)sl;
+ else if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
- writestruct(wd, DATA, "SpaceFile", 1, sl);
- if (sfile->params)
- writestruct(wd, DATA, "FileSelectParams", 1, sfile->params);
+ writestruct(wd, DATA, SpaceFile, 1, sl);
+ if (sfile->params) {
+ writestruct(wd, DATA, FileSelectParams, 1, sfile->params);
+ }
}
- else if (sl->spacetype==SPACE_SEQ) {
- writestruct(wd, DATA, "SpaceSeq", 1, sl);
+ else if (sl->spacetype == SPACE_SEQ) {
+ writestruct(wd, DATA, SpaceSeq, 1, sl);
}
- else if (sl->spacetype==SPACE_OUTLINER) {
- SpaceOops *so= (SpaceOops *)sl;
+ else if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
write_soops(wd, so, &tmp_mem_list);
}
- else if (sl->spacetype==SPACE_IMAGE) {
- SpaceImage *sima= (SpaceImage *)sl;
-
- writestruct(wd, DATA, "SpaceImage", 1, sl);
- if (sima->cumap)
- write_curvemapping(wd, sima->cumap);
+ else if (sl->spacetype == SPACE_IMAGE) {
+ writestruct(wd, DATA, SpaceImage, 1, sl);
}
- else if (sl->spacetype==SPACE_TEXT) {
- writestruct(wd, DATA, "SpaceText", 1, sl);
+ else if (sl->spacetype == SPACE_TEXT) {
+ writestruct(wd, DATA, SpaceText, 1, sl);
}
- else if (sl->spacetype==SPACE_SCRIPT) {
- SpaceScript *scr = (SpaceScript*)sl;
+ else if (sl->spacetype == SPACE_SCRIPT) {
+ SpaceScript *scr = (SpaceScript *)sl;
scr->but_refs = NULL;
- writestruct(wd, DATA, "SpaceScript", 1, sl);
+ writestruct(wd, DATA, SpaceScript, 1, sl);
}
- else if (sl->spacetype==SPACE_ACTION) {
- writestruct(wd, DATA, "SpaceAction", 1, sl);
+ else if (sl->spacetype == SPACE_ACTION) {
+ writestruct(wd, DATA, SpaceAction, 1, sl);
}
- else if (sl->spacetype==SPACE_NLA) {
- SpaceNla *snla= (SpaceNla *)sl;
-
- writestruct(wd, DATA, "SpaceNla", 1, snla);
- if (snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads);
+ else if (sl->spacetype == SPACE_NLA) {
+ SpaceNla *snla = (SpaceNla *)sl;
+
+ writestruct(wd, DATA, SpaceNla, 1, snla);
+ if (snla->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, snla->ads);
+ }
}
- else if (sl->spacetype==SPACE_TIME) {
- writestruct(wd, DATA, "SpaceTime", 1, sl);
+ else if (sl->spacetype == SPACE_TIME) {
+ writestruct(wd, DATA, SpaceTime, 1, sl);
}
- else if (sl->spacetype==SPACE_NODE) {
+ else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
bNodeTreePath *path;
- writestruct(wd, DATA, "SpaceNode", 1, snode);
-
- for (path=snode->treepath.first; path; path=path->next)
- writestruct(wd, DATA, "bNodeTreePath", 1, path);
+ writestruct(wd, DATA, SpaceNode, 1, snode);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ writestruct(wd, DATA, bNodeTreePath, 1, path);
+ }
}
- else if (sl->spacetype==SPACE_LOGIC) {
- writestruct(wd, DATA, "SpaceLogic", 1, sl);
+ else if (sl->spacetype == SPACE_LOGIC) {
+ writestruct(wd, DATA, SpaceLogic, 1, sl);
}
- else if (sl->spacetype==SPACE_CONSOLE) {
- SpaceConsole *con = (SpaceConsole*)sl;
+ else if (sl->spacetype == SPACE_CONSOLE) {
+ SpaceConsole *con = (SpaceConsole *)sl;
ConsoleLine *cl;
- for (cl=con->history.first; cl; cl=cl->next) {
+ for (cl = con->history.first; cl; cl = cl->next) {
/* 'len_alloc' is invalid on write, set from 'len' on read */
- writestruct(wd, DATA, "ConsoleLine", 1, cl);
- writedata(wd, DATA, cl->len+1, cl->line);
+ writestruct(wd, DATA, ConsoleLine, 1, cl);
+ writedata(wd, DATA, cl->len + 1, cl->line);
}
- writestruct(wd, DATA, "SpaceConsole", 1, sl);
+ writestruct(wd, DATA, SpaceConsole, 1, sl);
}
- else if (sl->spacetype==SPACE_USERPREF) {
- writestruct(wd, DATA, "SpaceUserPref", 1, sl);
+ else if (sl->spacetype == SPACE_USERPREF) {
+ writestruct(wd, DATA, SpaceUserPref, 1, sl);
}
- else if (sl->spacetype==SPACE_CLIP) {
- writestruct(wd, DATA, "SpaceClip", 1, sl);
+ else if (sl->spacetype == SPACE_CLIP) {
+ writestruct(wd, DATA, SpaceClip, 1, sl);
}
else if (sl->spacetype == SPACE_INFO) {
- writestruct(wd, DATA, "SpaceInfo", 1, sl);
+ writestruct(wd, DATA, SpaceInfo, 1, sl);
}
- sl= sl->next;
+ sl = sl->next;
}
}
- sc= sc->id.next;
+ sc = sc->id.next;
}
BLI_linklist_freeN(tmp_mem_list);
-
+
/* flush helps the compression for undo-save */
mywrite(wd, MYWRITE_FLUSH, 0);
}
-static void write_libraries(WriteData *wd, Main *main)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- ID *id;
- int a, tot;
- bool found_one;
-
- for (; main; main= main->next) {
-
- a=tot= set_listbasepointers(main, lbarray);
-
- /* test: is lib being used */
- if (main->curlib && main->curlib->packedfile)
- found_one = true;
- else {
- found_one = false;
- while (tot--) {
- for (id= lbarray[tot]->first; id; id= id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
- found_one = true;
- break;
- }
- }
- if (found_one) break;
- }
- }
-
- /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */
- /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
- * quit.blend and temp saves */
- if (found_one) {
- writestruct(wd, ID_LI, "Library", 1, main->curlib);
-
- if (main->curlib->packedfile) {
- PackedFile *pf = main->curlib->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- if (wd->current == NULL)
- printf("write packed .blend: %s\n", main->curlib->name);
- }
-
- while (a--) {
- for (id= lbarray[a]->first; id; id= id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
- if (!BKE_idcode_is_linkable(GS(id->name))) {
- printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
- "but is flagged as directly linked", id->name, main->curlib->filepath);
- BLI_assert(0);
- }
- writestruct(wd, ID_ID, "ID", 1, id);
- }
- }
- }
- }
- }
-}
-
static void write_bone(WriteData *wd, Bone *bone)
{
- Bone* cbone;
-
- // PATCH for upward compatibility after 2.37+ armature recode
+ /* PATCH for upward compatibility after 2.37+ armature recode */
bone->size[0] = bone->size[1] = bone->size[2] = 1.0f;
-
- // Write this bone
- writestruct(wd, DATA, "Bone", 1, bone);
+
+ /* Write this bone */
+ writestruct(wd, DATA, Bone, 1, bone);
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (bone->prop)
+ if (bone->prop) {
IDP_WriteProperty(bone->prop, wd);
-
- // Write Children
- cbone= bone->childbase.first;
- while (cbone) {
+ }
+
+ /* Write Children */
+ for (Bone *cbone = bone->childbase.first; cbone; cbone = cbone->next) {
write_bone(wd, cbone);
- cbone= cbone->next;
}
}
static void write_armatures(WriteData *wd, ListBase *idbase)
{
- bArmature *arm;
- Bone *bone;
+ bArmature *arm;
+ Bone *bone;
- arm=idbase->first;
+ arm = idbase->first;
while (arm) {
- if (arm->id.us>0 || wd->current) {
- writestruct(wd, ID_AR, "bArmature", 1, arm);
- if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd);
+ if (arm->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AR, bArmature, 1, arm);
+ write_iddata(wd, &arm->id);
- if (arm->adt) write_animdata(wd, arm->adt);
+ if (arm->adt) {
+ write_animdata(wd, arm->adt);
+ }
/* Direct data */
- bone= arm->bonebase.first;
+ bone = arm->bonebase.first;
while (bone) {
write_bone(wd, bone);
- bone=bone->next;
+ bone = bone->next;
}
}
- arm=arm->id.next;
+ arm = arm->id.next;
}
/* flush helps the compression for undo-save */
@@ -2998,32 +3203,37 @@ static void write_texts(WriteData *wd, ListBase *idbase)
Text *text;
TextLine *tmp;
- text= idbase->first;
+ text = idbase->first;
while (text) {
- if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
+ if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
+ text->flags &= ~TXT_ISEXT;
+ }
/* write LibData */
- writestruct(wd, ID_TXT, "Text", 1, text);
- if (text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
- if (text->id.properties) IDP_WriteProperty(text->id.properties, wd);
+ writestruct(wd, ID_TXT, Text, 1, text);
+ write_iddata(wd, &text->id);
+
+ if (text->name) {
+ writedata(wd, DATA, strlen(text->name) + 1, text->name);
+ }
if (!(text->flags & TXT_ISEXT)) {
/* now write the text data, in two steps for optimization in the readfunction */
- tmp= text->lines.first;
+ tmp = text->lines.first;
while (tmp) {
- writestruct(wd, DATA, "TextLine", 1, tmp);
- tmp= tmp->next;
+ writestruct(wd, DATA, TextLine, 1, tmp);
+ tmp = tmp->next;
}
- tmp= text->lines.first;
+ tmp = text->lines.first;
while (tmp) {
- writedata(wd, DATA, tmp->len+1, tmp->line);
- tmp= tmp->next;
+ writedata(wd, DATA, tmp->len + 1, tmp->line);
+ tmp = tmp->next;
}
}
- text= text->id.next;
+ text = text->id.next;
}
/* flush helps the compression for undo-save */
@@ -3034,16 +3244,18 @@ static void write_speakers(WriteData *wd, ListBase *idbase)
{
Speaker *spk;
- spk= idbase->first;
+ spk = idbase->first;
while (spk) {
- if (spk->id.us>0 || wd->current) {
+ if (spk->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_SPK, "Speaker", 1, spk);
- if (spk->id.properties) IDP_WriteProperty(spk->id.properties, wd);
+ writestruct(wd, ID_SPK, Speaker, 1, spk);
+ write_iddata(wd, &spk->id);
- if (spk->adt) write_animdata(wd, spk->adt);
+ if (spk->adt) {
+ write_animdata(wd, spk->adt);
+ }
}
- spk= spk->id.next;
+ spk = spk->id.next;
}
}
@@ -3051,22 +3263,22 @@ static void write_sounds(WriteData *wd, ListBase *idbase)
{
bSound *sound;
- PackedFile * pf;
+ PackedFile *pf;
- sound= idbase->first;
+ sound = idbase->first;
while (sound) {
- if (sound->id.us>0 || wd->current) {
+ if (sound->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_SO, "bSound", 1, sound);
- if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd);
+ writestruct(wd, ID_SO, bSound, 1, sound);
+ write_iddata(wd, &sound->id);
if (sound->packedfile) {
pf = sound->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
- sound= sound->id.next;
+ sound = sound->id.next;
}
/* flush helps the compression for undo-save */
@@ -3078,18 +3290,18 @@ static void write_groups(WriteData *wd, ListBase *idbase)
Group *group;
GroupObject *go;
- for (group= idbase->first; group; group= group->id.next) {
- if (group->id.us>0 || wd->current) {
+ for (group = idbase->first; group; group = group->id.next) {
+ if (group->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_GR, "Group", 1, group);
- if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
+ writestruct(wd, ID_GR, Group, 1, group);
+ write_iddata(wd, &group->id);
write_previews(wd, group->preview);
- go= group->gobject.first;
+ go = group->gobject.first;
while (go) {
- writestruct(wd, DATA, "GroupObject", 1, go);
- go= go->next;
+ writestruct(wd, DATA, GroupObject, 1, go);
+ go = go->next;
}
}
}
@@ -3098,15 +3310,15 @@ static void write_groups(WriteData *wd, ListBase *idbase)
static void write_nodetrees(WriteData *wd, ListBase *idbase)
{
bNodeTree *ntree;
-
- for (ntree=idbase->first; ntree; ntree= ntree->id.next) {
- if (ntree->id.us>0 || wd->current) {
- writestruct(wd, ID_NT, "bNodeTree", 1, ntree);
+
+ for (ntree = idbase->first; ntree; ntree = ntree->id.next) {
+ if (ntree->id.us > 0 || wd->current) {
+ writestruct(wd, ID_NT, bNodeTree, 1, ntree);
+ /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
+ * be linked, etc., so we write actual id data here only, for 'real' ID trees. */
+ write_iddata(wd, &ntree->id);
+
write_nodetree(wd, ntree);
-
- if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd);
-
- if (ntree->adt) write_animdata(wd, ntree->adt);
}
}
}
@@ -3116,11 +3328,12 @@ static void customnodes_add_deprecated_data(Main *mainvar)
{
FOREACH_NODETREE(mainvar, ntree, id) {
bNodeLink *link, *last_link = ntree->links.last;
-
+
/* only do this for node groups */
- if (id != &ntree->id)
+ if (id != &ntree->id) {
continue;
-
+ }
+
/* Forward compatibility for group nodes: add links to node tree interface sockets.
* These links are invalid by new rules (missing node pointer)!
* They will be removed again in customnodes_free_deprecated_data,
@@ -3131,7 +3344,7 @@ static void customnodes_add_deprecated_data(Main *mainvar)
for (link = ntree->links.first; link; link = link->next) {
bNode *fromnode = link->fromnode, *tonode = link->tonode;
bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock;
-
+
/* check both sides of the link, to handle direct input-to-output links */
if (fromnode->type == NODE_GROUP_INPUT) {
fromnode = NULL;
@@ -3142,22 +3355,23 @@ static void customnodes_add_deprecated_data(Main *mainvar)
tonode = NULL;
tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier);
}
-
+
if (!fromnode || !tonode) {
/* Note: not using nodeAddLink here, it asserts existing node pointers */
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link");
tlink->fromnode = fromnode;
tlink->fromsock = fromsock;
tlink->tonode = tonode;
- tlink->tosock= tosock;
+ tlink->tosock = tosock;
tosock->link = tlink;
tlink->flag |= NODE_LINK_VALID;
BLI_addtail(&ntree->links, tlink);
}
-
+
/* don't check newly created compatibility links */
- if (link == last_link)
+ if (link == last_link) {
break;
+ }
}
}
FOREACH_NODETREE_END
@@ -3167,11 +3381,12 @@ static void customnodes_free_deprecated_data(Main *mainvar)
{
FOREACH_NODETREE(mainvar, ntree, id) {
bNodeLink *link, *next_link;
-
+
for (link = ntree->links.first; link; link = next_link) {
next_link = link->next;
- if (link->fromnode == NULL || link->tonode == NULL)
+ if (link->fromnode == NULL || link->tonode == NULL) {
nodeRemLink(ntree, link);
+ }
}
}
FOREACH_NODETREE_END
@@ -3181,16 +3396,18 @@ static void customnodes_free_deprecated_data(Main *mainvar)
static void write_brushes(WriteData *wd, ListBase *idbase)
{
Brush *brush;
-
- for (brush=idbase->first; brush; brush= brush->id.next) {
- if (brush->id.us>0 || wd->current) {
- writestruct(wd, ID_BR, "Brush", 1, brush);
- if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
-
- if (brush->curve)
+
+ for (brush = idbase->first; brush; brush = brush->id.next) {
+ if (brush->id.us > 0 || wd->current) {
+ writestruct(wd, ID_BR, Brush, 1, brush);
+ write_iddata(wd, &brush->id);
+
+ if (brush->curve) {
write_curvemapping(wd, brush->curve);
- if (brush->gradient)
- writestruct(wd, DATA, "ColorBand", 1, brush->gradient);
+ }
+ if (brush->gradient) {
+ writestruct(wd, DATA, ColorBand, 1, brush->gradient);
+ }
}
}
}
@@ -3202,11 +3419,12 @@ static void write_palettes(WriteData *wd, ListBase *idbase)
for (palette = idbase->first; palette; palette = palette->id.next) {
if (palette->id.us > 0 || wd->current) {
PaletteColor *color;
- writestruct(wd, ID_PAL, "Palette", 1, palette);
- if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd);
+ writestruct(wd, ID_PAL, Palette, 1, palette);
+ write_iddata(wd, &palette->id);
- for (color = palette->colors.first; color; color= color->next)
- writestruct(wd, DATA, "PaletteColor", 1, color);
+ for (color = palette->colors.first; color; color = color->next) {
+ writestruct(wd, DATA, PaletteColor, 1, color);
+ }
}
}
}
@@ -3217,10 +3435,10 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase)
for (pc = idbase->first; pc; pc = pc->id.next) {
if (pc->id.us > 0 || wd->current) {
- writestruct(wd, ID_PC, "PaintCurve", 1, pc);
+ writestruct(wd, ID_PC, PaintCurve, 1, pc);
+ write_iddata(wd, &pc->id);
- writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points);
- if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd);
+ writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
}
}
}
@@ -3229,14 +3447,15 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks)
{
MovieTrackingTrack *track;
- track= tracks->first;
+ track = tracks->first;
while (track) {
- writestruct(wd, DATA, "MovieTrackingTrack", 1, track);
+ writestruct(wd, DATA, MovieTrackingTrack, 1, track);
- if (track->markers)
- writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers);
+ if (track->markers) {
+ writestruct(wd, DATA, MovieTrackingMarker, track->markersnr, track->markers);
+ }
- track= track->next;
+ track = track->next;
}
}
@@ -3248,53 +3467,54 @@ static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base)
plane_track;
plane_track = plane_track->next)
{
- writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track);
+ writestruct(wd, DATA, MovieTrackingPlaneTrack, 1, plane_track);
writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks);
- writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers);
+ writestruct(wd, DATA, MovieTrackingPlaneMarker, plane_track->markersnr, plane_track->markers);
}
}
static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction)
{
- if (reconstruction->camnr)
- writestruct(wd, DATA, "MovieReconstructedCamera", reconstruction->camnr, reconstruction->cameras);
+ if (reconstruction->camnr) {
+ writestruct(wd, DATA, MovieReconstructedCamera, reconstruction->camnr, reconstruction->cameras);
+ }
}
static void write_movieclips(WriteData *wd, ListBase *idbase)
{
MovieClip *clip;
- clip= idbase->first;
+ clip = idbase->first;
while (clip) {
- if (clip->id.us>0 || wd->current) {
- MovieTracking *tracking= &clip->tracking;
+ if (clip->id.us > 0 || wd->current) {
+ MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
- writestruct(wd, ID_MC, "MovieClip", 1, clip);
- if (clip->id.properties)
- IDP_WriteProperty(clip->id.properties, wd);
+ writestruct(wd, ID_MC, MovieClip, 1, clip);
+ write_iddata(wd, &clip->id);
- if (clip->adt)
+ if (clip->adt) {
write_animdata(wd, clip->adt);
+ }
write_movieTracks(wd, &tracking->tracks);
write_moviePlaneTracks(wd, &tracking->plane_tracks);
write_movieReconstruction(wd, &tracking->reconstruction);
- object= tracking->objects.first;
+ object = tracking->objects.first;
while (object) {
- writestruct(wd, DATA, "MovieTrackingObject", 1, object);
+ writestruct(wd, DATA, MovieTrackingObject, 1, object);
write_movieTracks(wd, &object->tracks);
write_moviePlaneTracks(wd, &object->plane_tracks);
write_movieReconstruction(wd, &object->reconstruction);
- object= object->next;
+ object = object->next;
}
}
- clip= clip->id.next;
+ clip = clip->id.next;
}
/* flush helps the compression for undo-save */
@@ -3310,16 +3530,18 @@ static void write_masks(WriteData *wd, ListBase *idbase)
if (mask->id.us > 0 || wd->current) {
MaskLayer *masklay;
- writestruct(wd, ID_MSK, "Mask", 1, mask);
+ writestruct(wd, ID_MSK, Mask, 1, mask);
+ write_iddata(wd, &mask->id);
- if (mask->adt)
+ if (mask->adt) {
write_animdata(wd, mask->adt);
+ }
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
MaskLayerShape *masklay_shape;
- writestruct(wd, DATA, "MaskLayer", 1, masklay);
+ writestruct(wd, DATA, MaskLayer, 1, masklay);
for (spline = masklay->splines.first; spline; spline = spline->next) {
int i;
@@ -3327,22 +3549,28 @@ static void write_masks(WriteData *wd, ListBase *idbase)
void *points_deform = spline->points_deform;
spline->points_deform = NULL;
- writestruct(wd, DATA, "MaskSpline", 1, spline);
- writestruct(wd, DATA, "MaskSplinePoint", spline->tot_point, spline->points);
+ writestruct(wd, DATA, MaskSpline, 1, spline);
+ writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points);
spline->points_deform = points_deform;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (point->tot_uw)
- writestruct(wd, DATA, "MaskSplinePointUW", point->tot_uw, point->uw);
+ if (point->tot_uw) {
+ writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw);
+ }
}
}
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- writestruct(wd, DATA, "MaskLayerShape", 1, masklay_shape);
- writedata(wd, DATA, masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data);
+ for (masklay_shape = masklay->splines_shapes.first;
+ masklay_shape;
+ masklay_shape = masklay_shape->next)
+ {
+ writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape);
+ writedata(wd, DATA,
+ masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE,
+ masklay_shape->data);
}
}
}
@@ -3357,65 +3585,65 @@ static void write_masks(WriteData *wd, ListBase *idbase)
static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleColorModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleColorModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleColorModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleColorModifier_Material";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleColorModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleColorModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleColorModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleColorModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleColorModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
- break;
- case LS_MODIFIER_MATERIAL:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
- break;
- case LS_MODIFIER_TANGENT:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp);
- break;
- case LS_MODIFIER_NOISE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Noise *)m)->color_ramp);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_TANGENT:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_NOISE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Noise *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
+ break;
}
}
}
@@ -3423,65 +3651,65 @@ static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleAlphaModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleAlphaModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleAlphaModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleAlphaModifier_Material";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleAlphaModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleAlphaModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleAlphaModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleAlphaModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleAlphaModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_TANGENT:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_NOISE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_NOISE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
+ break;
}
}
}
@@ -3489,65 +3717,65 @@ static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleThicknessModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleThicknessModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleThicknessModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleThicknessModifier_Material";
- break;
- case LS_MODIFIER_CALLIGRAPHY:
- struct_name = "LineStyleThicknessModifier_Calligraphy";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleThicknessModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleThicknessModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleThicknessModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleThicknessModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleThicknessModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Material);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Calligraphy);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_TANGENT:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve);
+ break;
}
}
}
@@ -3555,56 +3783,56 @@ static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifie
static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_SAMPLING:
- struct_name = "LineStyleGeometryModifier_Sampling";
- break;
- case LS_MODIFIER_BEZIER_CURVE:
- struct_name = "LineStyleGeometryModifier_BezierCurve";
- break;
- case LS_MODIFIER_SINUS_DISPLACEMENT:
- struct_name = "LineStyleGeometryModifier_SinusDisplacement";
- break;
- case LS_MODIFIER_SPATIAL_NOISE:
- struct_name = "LineStyleGeometryModifier_SpatialNoise";
- break;
- case LS_MODIFIER_PERLIN_NOISE_1D:
- struct_name = "LineStyleGeometryModifier_PerlinNoise1D";
- break;
- case LS_MODIFIER_PERLIN_NOISE_2D:
- struct_name = "LineStyleGeometryModifier_PerlinNoise2D";
- break;
- case LS_MODIFIER_BACKBONE_STRETCHER:
- struct_name = "LineStyleGeometryModifier_BackboneStretcher";
- break;
- case LS_MODIFIER_TIP_REMOVER:
- struct_name = "LineStyleGeometryModifier_TipRemover";
- break;
- case LS_MODIFIER_POLYGONIZATION:
- struct_name = "LineStyleGeometryModifier_Polygonalization";
- break;
- case LS_MODIFIER_GUIDING_LINES:
- struct_name = "LineStyleGeometryModifier_GuidingLines";
- break;
- case LS_MODIFIER_BLUEPRINT:
- struct_name = "LineStyleGeometryModifier_Blueprint";
- break;
- case LS_MODIFIER_2D_OFFSET:
- struct_name = "LineStyleGeometryModifier_2DOffset";
- break;
- case LS_MODIFIER_2D_TRANSFORM:
- struct_name = "LineStyleGeometryModifier_2DTransform";
- break;
- case LS_MODIFIER_SIMPLIFICATION:
- struct_name = "LineStyleGeometryModifier_Simplification";
- break;
- default:
- struct_name = "LineStyleGeometryModifier"; /* this should not happen */
+ case LS_MODIFIER_SAMPLING:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Sampling);
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BezierCurve);
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SinusDisplacement);
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SpatialNoise);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise1D);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise2D);
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BackboneStretcher);
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_TipRemover);
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Polygonalization);
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_GuidingLines);
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Blueprint);
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DOffset);
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DTransform);
+ break;
+ case LS_MODIFIER_SIMPLIFICATION:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Simplification);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
}
@@ -3614,27 +3842,94 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
int a;
for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) {
- if (linestyle->id.us>0 || wd->current) {
- writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle);
- if (linestyle->id.properties)
- IDP_WriteProperty(linestyle->id.properties, wd);
- if (linestyle->adt)
+ if (linestyle->id.us > 0 || wd->current) {
+ writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle);
+ write_iddata(wd, &linestyle->id);
+
+ if (linestyle->adt) {
write_animdata(wd, linestyle->adt);
+ }
+
write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
- for (a=0; a<MAX_MTEX; a++) {
- if (linestyle->mtex[a]) writestruct(wd, DATA, "MTex", 1, linestyle->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (linestyle->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]);
+ }
}
if (linestyle->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, linestyle->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree);
write_nodetree(wd, linestyle->nodetree);
}
}
}
}
+/* Keep it last of write_foodata functions. */
+static void write_libraries(WriteData *wd, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a, tot;
+ bool found_one;
+
+ for (; main; main = main->next) {
+
+ a = tot = set_listbasepointers(main, lbarray);
+
+ /* test: is lib being used */
+ if (main->curlib && main->curlib->packedfile) {
+ found_one = true;
+ }
+ else {
+ found_one = false;
+ while (tot--) {
+ for (id = lbarray[tot]->first; id; id = id->next) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ found_one = true;
+ break;
+ }
+ }
+ if (found_one) {
+ break;
+ }
+ }
+ }
+
+ /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */
+ /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
+ * quit.blend and temp saves */
+ if (found_one) {
+ writestruct(wd, ID_LI, Library, 1, main->curlib);
+ write_iddata(wd, &main->curlib->id);
+
+ if (main->curlib->packedfile) {
+ PackedFile *pf = main->curlib->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ if (wd->current == NULL) {
+ printf("write packed .blend: %s\n", main->curlib->name);
+ }
+ }
+
+ while (a--) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (!BKE_idcode_is_linkable(GS(id->name))) {
+ printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
+ "but is flagged as directly linked", id->name, main->curlib->filepath);
+ BLI_assert(0);
+ }
+ writestruct(wd, ID_ID, ID, 1, id);
+ }
+ }
+ }
+ }
+ }
+}
+
/* context is usually defined by WM, two cases where no WM is available:
* - for forward compatibility, curscreen has to be saved
* - for undofile, curscene needs to be saved */
@@ -3644,7 +3939,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
FileGlobal fg;
bScreen *screen;
char subvstr[8];
-
+
/* prevent mem checkers from complaining */
memset(fg.pad, 0, sizeof(fg.pad));
memset(fg.filename, 0, sizeof(fg.filename));
@@ -3653,20 +3948,20 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
current_screen_compat(mainvar, &screen, is_undo);
/* XXX still remap G */
- fg.curscreen= screen;
- fg.curscene= screen ? screen->scene : NULL;
+ fg.curscreen = screen;
+ fg.curscene = screen ? screen->scene : NULL;
/* prevent to save this, is not good convention, and feature with concerns... */
- fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME);
+ fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
- fg.globalf= G.f;
+ fg.globalf = G.f;
BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
-
- fg.subversion= BLENDER_SUBVERSION;
- fg.minversion= BLENDER_MINVERSION;
- fg.minsubversion= BLENDER_MINSUBVERSION;
+
+ fg.subversion = BLENDER_SUBVERSION;
+ fg.minversion = BLENDER_MINVERSION;
+ fg.minsubversion = BLENDER_MINSUBVERSION;
#ifdef WITH_BUILDINFO
{
extern unsigned long build_commit_timestamp;
@@ -3679,7 +3974,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.build_commit_timestamp = 0;
BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash));
#endif
- writestruct(wd, GLOB, "FileGlobal", 1, &fg);
+ writestruct(wd, GLOB, FileGlobal, 1, &fg);
}
/* preview image, first 2 values are width and height
@@ -3694,11 +3989,11 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
}
/* if MemFile * there's filesave to memory */
-static int write_file_handle(
+static bool write_file_handle(
Main *mainvar,
WriteWrap *ww,
MemFile *compare, MemFile *current,
- int write_user_block, int write_flags, const BlendThumbnail *thumb)
+ int write_flags, const BlendThumbnail *thumb)
{
BHead bhead;
ListBase mainlist;
@@ -3733,42 +4028,42 @@ static int write_file_handle(
write_global(wd, write_flags, mainvar);
write_windowmanagers(wd, &mainvar->wm);
- write_screens (wd, &mainvar->screen);
- write_movieclips (wd, &mainvar->movieclip);
- write_masks (wd, &mainvar->mask);
- write_scenes (wd, &mainvar->scene);
- write_curves (wd, &mainvar->curve);
- write_mballs (wd, &mainvar->mball);
- write_images (wd, &mainvar->image);
- write_cameras (wd, &mainvar->camera);
- write_lamps (wd, &mainvar->lamp);
- write_lattices (wd, &mainvar->latt);
- write_vfonts (wd, &mainvar->vfont);
- write_keys (wd, &mainvar->key);
- write_worlds (wd, &mainvar->world);
- write_texts (wd, &mainvar->text);
- write_speakers (wd, &mainvar->speaker);
- write_sounds (wd, &mainvar->sound);
- write_groups (wd, &mainvar->group);
+ write_screens(wd, &mainvar->screen);
+ write_movieclips(wd, &mainvar->movieclip);
+ write_masks(wd, &mainvar->mask);
+ write_scenes(wd, &mainvar->scene);
+ write_curves(wd, &mainvar->curve);
+ write_mballs(wd, &mainvar->mball);
+ write_images(wd, &mainvar->image);
+ write_cameras(wd, &mainvar->camera);
+ write_lamps(wd, &mainvar->lamp);
+ write_lattices(wd, &mainvar->latt);
+ write_vfonts(wd, &mainvar->vfont);
+ write_keys(wd, &mainvar->key);
+ write_worlds(wd, &mainvar->world);
+ write_texts(wd, &mainvar->text);
+ write_speakers(wd, &mainvar->speaker);
+ write_sounds(wd, &mainvar->sound);
+ write_groups(wd, &mainvar->group);
write_armatures(wd, &mainvar->armature);
- write_actions (wd, &mainvar->action);
- write_objects (wd, &mainvar->object);
+ write_actions(wd, &mainvar->action);
+ write_objects(wd, &mainvar->object);
write_materials(wd, &mainvar->mat);
- write_textures (wd, &mainvar->tex);
- write_meshes (wd, &mainvar->mesh);
+ write_textures(wd, &mainvar->tex);
+ write_meshes(wd, &mainvar->mesh);
write_particlesettings(wd, &mainvar->particle);
write_nodetrees(wd, &mainvar->nodetree);
- write_brushes (wd, &mainvar->brush);
- write_palettes (wd, &mainvar->palettes);
- write_paintcurves (wd, &mainvar->paintcurves);
- write_gpencils (wd, &mainvar->gpencil);
+ write_brushes(wd, &mainvar->brush);
+ write_palettes(wd, &mainvar->palettes);
+ write_paintcurves(wd, &mainvar->paintcurves);
+ write_gpencils(wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
write_libraries(wd, mainvar->next);
- if (write_user_block) {
+ if (write_flags & G_FILE_USERPREFS) {
write_userdef(wd);
}
-
+
/* dna as last, because (to be implemented) test for which structs are written */
writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
@@ -3785,7 +4080,7 @@ static int write_file_handle(
/* end of file */
memset(&bhead, 0, sizeof(BHead));
- bhead.code= ENDB;
+ bhead.code = ENDB;
mywrite(wd, &bhead, sizeof(BHead));
blo_join_main(&mainlist);
@@ -3798,16 +4093,19 @@ static int write_file_handle(
static bool do_history(const char *name, ReportList *reports)
{
char tempname1[FILE_MAX], tempname2[FILE_MAX];
- int hisnr= U.versions;
-
- if (U.versions==0) return 0;
- if (strlen(name)<2) {
+ int hisnr = U.versions;
+
+ if (U.versions == 0) {
+ return 0;
+ }
+
+ if (strlen(name) < 2) {
BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
return 1;
}
while (hisnr > 1) {
- BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1);
+ BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1);
if (BLI_exists(tempname1)) {
BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
@@ -3839,8 +4137,7 @@ bool BLO_write_file(
Main *mainvar, const char *filepath, int write_flags,
ReportList *reports, const BlendThumbnail *thumb)
{
- char tempname[FILE_MAX+1];
- int err, write_user_block;
+ char tempname[FILE_MAX + 1];
eWriteWrapType ww_type;
WriteWrap ww;
@@ -3895,13 +4192,13 @@ bool BLO_write_file(
}
}
- write_user_block= write_flags & G_FILE_USERPREFS;
-
- if (write_flags & G_FILE_RELATIVE_REMAP)
- BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
+ if (write_flags & G_FILE_RELATIVE_REMAP) {
+ /* note, making relative to something OTHER then G.main->name */
+ BKE_bpath_relative_convert(mainvar, filepath, NULL);
+ }
/* actual file writing */
- err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb);
+ const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, thumb);
ww.close(&ww);
@@ -3940,9 +4237,9 @@ bool BLO_write_file(
*/
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
- int err;
+ write_flags &= ~G_FILE_USERPREFS;
- err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL);
+ const bool err = write_file_handle(mainvar, NULL, compare, current, write_flags, NULL);
return (err == 0);
}
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 3fe888736f0..d6ca7239e39 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -904,7 +904,7 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
}
else if (ese->htype == BM_FACE) {
BMFace *efa = (BMFace *)ese->ele;
- BM_face_calc_plane(efa, r_plane);
+ BM_face_calc_tangent_auto(efa, r_plane);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ed1bd16b2e4..32aa80a4e73 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-allocatges 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 62b29e61d08..fff6bea044c 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -286,64 +286,258 @@ float BM_face_calc_perimeter(const BMFace *f)
return perimeter;
}
-void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3])
+/**
+ * Utility function to calculate the edge which is most different from the other two.
+ *
+ * \return The first edge index, where the second vertex is ``(index + 1) % 3``.
+ */
+static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
{
- float lens[3];
+ /* find the most 'unique' loop, (greatest difference to others) */
+#if 1
+ /* optimized version that avoids sqrt */
float difs[3];
- int order[3] = {0, 1, 2};
+ for (int i_prev = 1, i_curr = 2, i_next = 0;
+ i_next < 3;
+ i_prev = i_curr, i_curr = i_next++)
+ {
+ const float *co = verts[i_curr]->co;
+ const float *co_other[2] = {verts[i_prev]->co, verts[i_next]->co};
+ float proj_dir[3];
+ mid_v3_v3v3(proj_dir, co_other[0], co_other[1]);
+ sub_v3_v3(proj_dir, co);
+
+ float proj_pair[2][3];
+ project_v3_v3v3(proj_pair[0], co_other[0], proj_dir);
+ project_v3_v3v3(proj_pair[1], co_other[1], proj_dir);
+ difs[i_next] = len_squared_v3v3(proj_pair[0], proj_pair[1]);
+ }
+#else
+ const float lens[3] = {
+ len_v3v3(verts[0]->co, verts[1]->co),
+ len_v3v3(verts[1]->co, verts[2]->co),
+ len_v3v3(verts[2]->co, verts[0]->co),
+ };
+ const float difs[3] = {
+ fabsf(lens[1] - lens[2]),
+ fabsf(lens[2] - lens[0]),
+ fabsf(lens[0] - lens[1]),
+ };
+#endif
- lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
- lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
- lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
+ int order[3] = {0, 1, 2};
+ axis_sort_v3(difs, order);
- /* find the shortest or the longest loop */
- difs[0] = fabsf(lens[1] - lens[2]);
- difs[1] = fabsf(lens[2] - lens[0]);
- difs[2] = fabsf(lens[0] - lens[1]);
+ return order[0];
+}
- axis_sort_v3(difs, order);
- sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co);
+/**
+ * Calculate a tangent from any 3 vertices.
+ *
+ * The tangent aligns to the most *unique* edge
+ * (the edge most unlike the other two).
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
+{
+ const int index = bm_vert_tri_find_unique_edge(verts);
+
+ sub_v3_v3v3(r_tangent, verts[index]->co, verts[(index + 1) % 3]->co);
+
+ normalize_v3(r_tangent);
}
/**
- * Compute a meaningful direction along the face (use for manipulator axis).
- * \note result isnt normalized.
+ * Calculate a tangent from any 3 vertices,
+ *
+ * The tangent follows the center-line formed by the most unique edges center
+ * and the opposite vertex.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
*/
-void BM_face_calc_plane(const BMFace *f, float r_plane[3])
+void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
+{
+ const int index = bm_vert_tri_find_unique_edge(verts);
+
+ const float *v_a = verts[index]->co;
+ const float *v_b = verts[(index + 1) % 3]->co;
+ const float *v_other = verts[(index + 2) % 3]->co;
+
+ mid_v3_v3v3(r_tangent, v_a, v_b);
+ sub_v3_v3v3(r_tangent, v_other, r_tangent);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute the tanget of the face, using the longest edge.
+ */
+void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
+{
+ const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+
+ sub_v3_v3v3(r_tangent, l_long->v->co, l_long->next->v->co);
+
+ normalize_v3(r_tangent);
+
+}
+
+/**
+ * Compute the tanget of the face, using the two longest disconected edges.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
BMVert *verts[3];
BM_face_as_array_vert_tri((BMFace *)f, verts);
- BM_vert_tri_calc_plane(verts, r_plane);
+ BM_vert_tri_calc_tangent_edge_pair(verts, r_tangent);
}
else if (f->len == 4) {
+ /* Use longest edge pair */
BMVert *verts[4];
float vec[3], vec_a[3], vec_b[3];
- // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
BM_face_as_array_vert_quad((BMFace *)f, verts);
sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co);
sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co);
- add_v3_v3v3(r_plane, vec_a, vec_b);
+ add_v3_v3v3(r_tangent, vec_a, vec_b);
sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co);
sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co);
add_v3_v3v3(vec, vec_a, vec_b);
- /* use the biggest edge length */
- if (len_squared_v3(r_plane) < len_squared_v3(vec)) {
- copy_v3_v3(r_plane, vec);
+ /* use the longest edge length */
+ if (len_squared_v3(r_tangent) < len_squared_v3(vec)) {
+ copy_v3_v3(r_tangent, vec);
}
}
else {
- const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+ /* For ngons use two longest disconnected edges */
+ BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+ BMLoop *l_long_other = NULL;
- sub_v3_v3v3(r_plane, l_long->v->co, l_long->next->v->co);
+ float len_max_sq = 0.0f;
+ float vec_a[3], vec_b[3];
+
+ BMLoop *l_iter = l_long->prev->prev;
+ BMLoop *l_last = l_long->next;
+
+ do {
+ const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co);
+ if (len_sq >= len_max_sq) {
+ l_long_other = l_iter;
+ len_max_sq = len_sq;
+ }
+ } while ((l_iter = l_iter->prev) != l_last);
+
+ sub_v3_v3v3(vec_a, l_long->next->v->co, l_long->v->co);
+ sub_v3_v3v3(vec_b, l_long_other->v->co, l_long_other->next->v->co);
+ add_v3_v3v3(r_tangent, vec_a, vec_b);
+
+ /* Edges may not be opposite side of the ngon,
+ * this could cause problems for ngons with multiple-aligned edges of the same length.
+ * Fallback to longest edge. */
+ if (UNLIKELY(normalize_v3(r_tangent) == 0.0f)) {
+ normalize_v3_v3(r_tangent, vec_a);
+ }
}
+}
- normalize_v3(r_plane);
+/**
+ * Compute the tanget of the face, using the edge farthest away from any vertex in the face.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
+{
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ /* incase of degenerate faces */
+ zero_v3(r_tangent);
+
+ /* warning: O(n^2) loop here, take care! */
+ float dist_max_sq = 0.0f;
+ do {
+ BMLoop *l_iter_other = l_iter->next;
+ BMLoop *l_iter_last = l_iter->prev;
+ do {
+ BLI_assert(!ELEM(l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co));
+ float co_other[3], vec[3];
+ closest_to_line_segment_v3(co_other, l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co);
+ sub_v3_v3v3(vec, l_iter->v->co, co_other);
+
+ const float dist_sq = len_squared_v3(vec);
+ if (dist_sq > dist_max_sq) {
+ dist_max_sq = dist_sq;
+ copy_v3_v3(r_tangent, vec);
+ }
+ } while ((l_iter_other = l_iter_other->next) != l_iter_last);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute the tanget of the face, using longest distance between vertices on the face.
+ *
+ * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
+ */
+void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
+{
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ /* incase of degenerate faces */
+ zero_v3(r_tangent);
+
+ /* warning: O(n^2) loop here, take care! */
+ float dist_max_sq = 0.0f;
+ do {
+ BMLoop *l_iter_other = l_iter->next;
+ do {
+ float vec[3];
+ sub_v3_v3v3(vec, l_iter->v->co, l_iter_other->v->co);
+
+ const float dist_sq = len_squared_v3(vec);
+ if (dist_sq > dist_max_sq) {
+ dist_max_sq = dist_sq;
+ copy_v3_v3(r_tangent, vec);
+ }
+ } while ((l_iter_other = l_iter_other->next) != l_iter);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute a meaningful direction along the face (use for manipulator axis).
+ *
+ * \note Callers shouldn't depend on the *exact* method used here.
+ */
+void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
+{
+ if (f->len == 3) {
+ /* most 'unique' edge of a triangle */
+ BMVert *verts[3];
+ BM_face_as_array_vert_tri((BMFace *)f, verts);
+ BM_vert_tri_calc_tangent_edge(verts, r_tangent);
+ }
+ else if (f->len == 4) {
+ /* longest edge pair of a quad */
+ BM_face_calc_tangent_edge_pair((BMFace *)f, r_tangent);
+ }
+ else {
+ /* longest edge of an ngon */
+ BM_face_calc_tangent_edge((BMFace *)f, r_tangent);
+ }
}
/**
@@ -842,6 +1036,7 @@ void BM_face_triangulate(
const int quad_method,
const int ngon_method,
const bool use_tag,
+ /* use for ngons only! */
MemArena *pf_arena,
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 8f0df81af73..1e50a504875 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -45,7 +45,11 @@ float BM_face_calc_normal_vcos(
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_face_calc_plane(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_auto(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_center_bounds(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean_vcos(
@@ -90,6 +94,7 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
-void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]);
+void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
+void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
#endif /* __BMESH_POLYGON_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index c224a1ad587..5ee0e904a33 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -97,15 +97,27 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
return NULL;
}
+static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3])
+{
+ float dir[3];
+ sub_v3_v3v3(dir, v1, v2);
+ mul_v2_m3v3(out, axis_mat, dir);
+ normalize_v2(out);
+}
+
+
+/**
+ * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists
+ * when making changed to edge picking logic.
+ */
static bool bm_face_split_edgenet_find_loop_pair(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init,
+ const float face_normal[3], float face_normal_matrix[3][3],
BMEdge *e_pair[2])
{
/* Always find one boundary edge (to determine winding)
* and one wire (if available), otherwise another boundary.
*/
- BMIter iter;
- BMEdge *e;
/* detect winding */
BMLoop *l_walk;
@@ -116,18 +128,22 @@ static bool bm_face_split_edgenet_find_loop_pair(
int edges_boundary_len = 0;
int edges_wire_len = 0;
- BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) {
- if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
- const unsigned int count = bm_edge_flagged_radial_count(e);
- if (count == 1) {
- BLI_SMALLSTACK_PUSH(edges_boundary, e);
- edges_boundary_len++;
- }
- else if (count == 0) {
- BLI_SMALLSTACK_PUSH(edges_wire, e);
- edges_wire_len++;
+ {
+ BMEdge *e, *e_first;
+ e = e_first = v_init->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ BLI_SMALLSTACK_PUSH(edges_boundary, e);
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ BLI_SMALLSTACK_PUSH(edges_wire, e);
+ edges_wire_len++;
+ }
}
- }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first);
}
/* first edge should always be boundary */
@@ -136,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
+ /* use to hold boundary OR wire edges */
+ BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
+
/* attempt one boundary and one wire, or 2 boundary */
if (edges_wire_len == 0) {
- if (edges_boundary_len >= 2) {
+ if (edges_boundary_len > 1) {
e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
+
+ if (edges_boundary_len > 2) {
+ BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
+ }
}
else {
/* one boundary and no wire */
@@ -148,27 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
else {
e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
-
if (edges_wire_len > 1) {
- BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
- BMVert *v_next;
- float angle_best;
-
- v_next = BM_edge_other_vert(e_pair[1], v_init);
- angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
-
- while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
- float angle_test;
- v_next = BM_edge_other_vert(e, v_init);
- angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
- if (angle_test < angle_best) {
- angle_best = angle_test;
- e_pair[1] = e;
- }
- }
+ BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
}
}
+ /* if we swapped above, search this list for the best edge */
+ if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) {
+ /* find the best edge in 'edge_list' to use for 'e_pair[1]' */
+ const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
+ const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init);
+
+ float dir_prev[2], dir_next[2];
+
+ normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co);
+ normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co);
+ float angle_best_cos = dot_v2v2(dir_next, dir_prev);
+
+ BMEdge *e;
+ while ((e = BLI_SMALLSTACK_POP(edges_search))) {
+ v_next = BM_edge_other_vert(e, v_init);
+ float dir_test[2];
+
+ normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co);
+ const float angle_test_cos = dot_v2v2(dir_prev, dir_test);
+
+ if (angle_test_cos > angle_best_cos) {
+ angle_best_cos = angle_test_cos;
+ e_pair[1] = e;
+ }
+ }
+ }
/* flip based on winding */
l_walk = bm_edge_flagged_radial_first(e_pair[0]);
@@ -186,6 +219,58 @@ static bool bm_face_split_edgenet_find_loop_pair(
return true;
}
+/**
+ * A reduced version of #bm_face_split_edgenet_find_loop_pair
+ * that only checks if it would return true.
+ *
+ * \note There is no use in caching resulting edges here,
+ * since between this check and running #bm_face_split_edgenet_find_loop,
+ * the selected edges may have had faces attached.
+ */
+static bool bm_face_split_edgenet_find_loop_pair_exists(
+ BMVert *v_init)
+{
+ int edges_boundary_len = 0;
+ int edges_wire_len = 0;
+
+ {
+ BMEdge *e, *e_first;
+ e = e_first = v_init->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ edges_wire_len++;
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first);
+ }
+
+ /* first edge should always be boundary */
+ if (edges_boundary_len == 0) {
+ return false;
+ }
+
+ /* attempt one boundary and one wire, or 2 boundary */
+ if (edges_wire_len == 0) {
+ if (edges_boundary_len >= 2) {
+ /* pass */
+ }
+ else {
+ /* one boundary and no wire */
+ return false;
+ }
+ }
+ else {
+ /* pass */
+ }
+
+ return true;
+}
+
static bool bm_face_split_edgenet_find_loop_walk(
BMVert *v_init, const float face_normal[3],
/* cache to avoid realloc every time */
@@ -232,9 +317,6 @@ static bool bm_face_split_edgenet_find_loop_walk(
* alternatives are stored in the 'vert_stack'.
*/
while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
- BMIter eiter;
- BMEdge *e_next;
-
#ifdef USE_FASTPATH_NOFORK
walk_nofork:
#else
@@ -250,35 +332,42 @@ walk_nofork:
goto finally;
}
- BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
- if ((v->e != e_next) &&
- (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
- (bm_edge_flagged_radial_count(e_next) < 2))
- {
- BMVert *v_next;
+ BMEdge *e_next, *e_first;
+ e_first = v->e;
+ e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */
+
+ /* in rare cases there may be edges with a single connecting vertex */
+ if (e_next != e_first) {
+ do {
+ if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
+ (bm_edge_flagged_radial_count(e_next) < 2))
+ {
+ BMVert *v_next;
- v_next = BM_edge_other_vert(e_next, v);
+ v_next = BM_edge_other_vert(e_next, v);
+ BLI_assert(v->e != e_next);
#ifdef DEBUG_PRINT
- /* indent and print */
- {
- BMVert *_v = v;
- do {
- printf(" ");
- } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
- printf("vert %d -> %d (add=%d)\n",
- BM_elem_index_get(v), BM_elem_index_get(v_next),
- BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
- }
+ /* indent and print */
+ {
+ BMVert *_v = v;
+ do {
+ printf(" ");
+ } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
+ printf("vert %d -> %d (add=%d)\n",
+ BM_elem_index_get(v), BM_elem_index_get(v_next),
+ BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
+ }
#endif
- if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
- eo = STACK_PUSH_RET_PTR(edge_order);
- eo->v = v_next;
+ if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
+ eo = STACK_PUSH_RET_PTR(edge_order);
+ eo->v = v_next;
- v_next->e = e_next;
+ v_next->e = e_next;
+ }
}
- }
+ } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
}
#ifdef USE_FASTPATH_NOFORK
@@ -329,7 +418,7 @@ finally:
}
static bool bm_face_split_edgenet_find_loop(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
struct VertOrder *edge_order, const unsigned int edge_order_len,
BMVert **r_face_verts, int *r_face_verts_len)
@@ -337,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop(
BMEdge *e_pair[2];
BMVert *v;
- if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
+ if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) {
return false;
}
@@ -432,12 +521,18 @@ bool BM_face_split_edgenet(
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
} while ((l_iter = l_iter->next) != l_first);
+ float face_normal_matrix[3][3];
+ axis_dominant_v3_to_m3(face_normal_matrix, f->no);
+
/* any vert can be used to begin with */
STACK_PUSH(vert_queue, l_first->v);
while ((v = STACK_POP(vert_queue))) {
- if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
+ if (bm_face_split_edgenet_find_loop(
+ v, f->no, face_normal_matrix,
+ edge_order, edge_order_len, face_verts, &face_verts_len))
+ {
BMFace *f_new;
f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
@@ -447,7 +542,6 @@ bool BM_face_split_edgenet(
}
if (f_new) {
- bool l_prev_is_boundary;
BLI_array_append(face_arr, f_new);
copy_v3_v3(f_new->no, f->no);
@@ -463,13 +557,10 @@ bool BM_face_split_edgenet(
/* add new verts to keep finding loops for
* (verts between boundary and manifold edges) */
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
- l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1);
do {
- bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1);
- if (l_prev_is_boundary != l_iter_is_boundary) {
+ if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) {
STACK_PUSH(vert_queue, l_iter->v);
}
- l_prev_is_boundary = l_iter_is_boundary;
} while ((l_iter = l_iter->next) != l_first);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 9b3a147301d..d8d297c9298 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -67,12 +67,13 @@ enum {
_FLAG_MV = (1 << 1), /* make face, vertex */
_FLAG_OVERLAP = (1 << 2), /* general overlap flag */
_FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */
+ _FLAG_WALK_ALT = (1 << 4), /* same as _FLAG_WALK, for when a second tag is needed */
_FLAG_ELEM_CHECK = (1 << 7), /* reserved for bmesh_elem_check */
};
#define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0
-#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= ~(f)); } (void)0
+#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0
#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f))
#define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0
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 34f59aad4f1..9bb67ed9341 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -85,7 +85,7 @@ static bool bm_face_split_by_concave(
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
const int quad_method = 0, ngon_method = 0; /* beauty */
- LinkNode *r_faces_double = NULL;
+ LinkNode *faces_double = NULL;
float normal[3];
BLI_assert(f_base->len > 3);
@@ -96,7 +96,7 @@ static bool bm_face_split_by_concave(
bm, f_base,
faces_array, &faces_array_tot,
edges_array, &edges_array_tot,
- &r_faces_double,
+ &faces_double,
quad_method, ngon_method, false,
pf_arena,
pf_heap, pf_ehash);
@@ -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);
}
}
}
@@ -163,6 +163,13 @@ static bool bm_face_split_by_concave(
BLI_heap_clear(pf_heap, NULL);
BLI_edgehash_clear_ex(pf_ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
+
return true;
}
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..f2a8e05d763 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;
}
@@ -689,11 +692,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 +704,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 +729,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 a1f40b31fc7..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,27 +222,18 @@ 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 if (!BM_edge_exists(v1, v2)) {
- BMEdge *e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
-
- /* low level selection, not essential but means we can keep
- * edge selection valid on auto-merge for example. */
- if ((BM_elem_flag_test(e, BM_ELEM_SELECT) == true) &&
- (BM_elem_flag_test(e_new, BM_ELEM_SELECT) == false))
- {
- BM_elem_flag_disable(e, BM_ELEM_SELECT);
- BM_elem_flag_merge_into(e_new, e_new, e);
- BM_elem_flag_enable(e_new, BM_ELEM_SELECT);
- /* bm->totedgesel remains valid */
- }
- else {
- BM_elem_flag_merge_into(e_new, e_new, e);
+ else {
+ /* always merge flags, even for edges we already created */
+ BMEdge *e_new = BM_edge_exists(v1, v2);
+ if (e_new == NULL) {
+ e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
}
+ BM_elem_flag_merge(e_new, e);
}
- BMO_elem_flag_enable(bm, e, ELE_DEL);
+ BMO_edge_flag_enable(bm, e, ELE_DEL);
}
}
@@ -253,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);
@@ -270,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);
}
@@ -448,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));
@@ -519,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));
@@ -615,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;
}
@@ -623,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;
}
@@ -637,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);
}
@@ -692,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..8d672b32caa 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -384,7 +384,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 +419,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 +449,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 +698,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 +711,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 +724,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 +802,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 +817,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 +837,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 +1023,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 +1043,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 +1062,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 +1082,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 +1094,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 +1110,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 +1162,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 +1245,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 6fb09c76ea4..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);
}
}
}
@@ -244,29 +244,33 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW);
BMO_op_finish(bm, &bmop);
}
-
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
if (use_dissolve) {
- BMO_ITER (e, &siter, op->slots_out, "geom.out", BM_EDGE) {
- if (LIKELY(e->l)) { /* in rare cases the edges face will have already been removed from the edge */
- BMFace *f_new;
- f_new = BM_faces_join_pair(bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
- if (f_new) {
- BMO_elem_flag_enable(bm, f_new, ELE_NEW);
- BM_edge_kill(bm, e);
+ BMEdge *e_next;
+ BMIter iter;
+
+ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
+ 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(
+ bm, e->l->f,
+ e->l->radial_next->f, e,
+ false); /* join faces */
+ if (f_new) {
+ BMO_face_flag_enable(bm, f_new, ELE_NEW);
+ BM_edge_kill(bm, e);
+ }
+ else {
+ BMO_error_clear(bm);
+ }
}
else {
- BMO_error_clear(bm);
+ BM_edge_kill(bm, e);
}
}
- else {
- BM_edge_kill(bm, e);
- }
}
-
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
}
+
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
}
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_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 0a5e5aba86b..52a0df5b9d1 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -34,6 +34,14 @@
#include "BLI_math.h"
#include "BLI_quadric.h"
#include "BLI_heap.h"
+#include "BLI_linklist.h"
+#include "BLI_alloca.h"
+#include "BLI_memarena.h"
+#include "BLI_edgehash.h"
+#include "BLI_polyfill2d.h"
+#include "BLI_polyfill2d_beautify.h"
+#include "BLI_stackdefines.h"
+
#include "BKE_customdata.h"
@@ -55,14 +63,14 @@
/* if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */
#define USE_TOPOLOGY_FALLBACK
#ifdef USE_TOPOLOGY_FALLBACK
-# define TOPOLOGY_FALLBACK_EPS FLT_EPSILON
+/* cost is calculated with double precision, it's ok to use a very small epsilon, see T48154. */
+# define TOPOLOGY_FALLBACK_EPS 1e-12f
#endif
-/* these checks are for rare cases that we can't avoid since they are valid meshes still */
-#define USE_SAFETY_CHECKS
-
#define BOUNDARY_PRESERVE_WEIGHT 100.0f
-#define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */
+/* Uses double precision, impacts behavior on near-flat surfaces,
+ * cane give issues with very small faces. 1e-2 is too big, see: T48154. */
+#define OPTIMIZE_EPS 1e-8
#define COST_INVALID FLT_MAX
typedef enum CD_UseFlag {
@@ -134,8 +142,8 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
}
-static void bm_decim_calc_target_co(
- BMEdge *e, float optimize_co[3],
+static void bm_decim_calc_target_co_db(
+ BMEdge *e, double optimize_co[3],
const Quadric *vquadrics)
{
/* compute an edge contraction target for edge 'e'
@@ -152,10 +160,22 @@ static void bm_decim_calc_target_co(
return; /* all is good */
}
else {
- mid_v3_v3v3(optimize_co, e->v1->co, e->v2->co);
+ optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]);
+ optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]);
+ optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]);
}
}
+static void bm_decim_calc_target_co_fl(
+ BMEdge *e, float optimize_co[3],
+ const Quadric *vquadrics)
+{
+ double optimize_co_db[3];
+ bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics);
+ copy_v3fl_v3db(optimize_co, optimize_co_db);
+}
+
+
static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
{
BMIter liter;
@@ -234,8 +254,6 @@ static void bm_decim_build_edge_cost_single(
const float *vweights, const float vweight_factor,
Heap *eheap, HeapNode **eheap_table)
{
- const Quadric *q1, *q2;
- float optimize_co[3];
float cost;
if (eheap_table[BM_elem_index_get(e)]) {
@@ -273,15 +291,17 @@ static void bm_decim_build_edge_cost_single(
}
/* end sanity check */
+ {
+ double optimize_co[3];
+ bm_decim_calc_target_co_db(e, optimize_co, vquadrics);
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
-
- q1 = &vquadrics[BM_elem_index_get(e->v1)];
- q2 = &vquadrics[BM_elem_index_get(e->v2)];
-
- cost = (BLI_quadric_evaluate(q1, optimize_co) +
- BLI_quadric_evaluate(q2, optimize_co));
+ const Quadric *q1, *q2;
+ q1 = &vquadrics[BM_elem_index_get(e->v1)];
+ q2 = &vquadrics[BM_elem_index_get(e->v2)];
+ cost = (BLI_quadric_evaluate(q1, optimize_co) +
+ BLI_quadric_evaluate(q2, optimize_co));
+ }
/* note, 'cost' shouldn't be negative but happens sometimes with small values.
* this can cause faces that make up a flat surface to over-collapse, see [#37121] */
@@ -472,12 +492,58 @@ static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float li
*
* \return true if any faces were triangulated.
*/
+static bool bm_face_triangulate(
+ BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot,
-static bool bm_decim_triangulate_begin(BMesh *bm)
+ MemArena *pf_arena,
+ /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
+ struct Heap *pf_heap, struct EdgeHash *pf_ehash)
+{
+ const int f_base_len = f_base->len;
+ int faces_array_tot = f_base_len - 3;
+ int edges_array_tot = f_base_len - 3;
+ BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
+ const int quad_method = 0, ngon_method = 0; /* beauty */
+
+ bool has_cut = false;
+
+ const int f_index = BM_elem_index_get(f_base);
+
+ BM_face_triangulate(
+ bm, f_base,
+ faces_array, &faces_array_tot,
+ edges_array, &edges_array_tot,
+ r_faces_double,
+ quad_method, ngon_method, false,
+ pf_arena,
+ pf_heap, pf_ehash);
+
+ for (int i = 0; i < edges_array_tot; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = edges_array[i]->l;
+ do {
+ BM_elem_index_set(l_iter, f_index); /* set_dirty */
+ has_cut = true;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ for (int i = 0; i < faces_array_tot; i++) {
+ BM_face_normal_update(faces_array[i]);
+ }
+
+ *r_edges_tri_tot += edges_array_tot;
+
+ return has_cut;
+}
+
+
+static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
{
BMIter iter;
BMFace *f;
- // bool has_quad; // could optimize this a little
+ bool has_quad = false;
+ bool has_ngon = false;
bool has_cut = false;
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
@@ -492,98 +558,104 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
BM_elem_index_set(l_iter, -1); /* set_dirty */
} while ((l_iter = l_iter->next) != l_first);
- // has_quad |= (f->len == 4)
+ has_quad |= (f->len > 3);
+ has_ngon |= (f->len > 4);
}
bm->elem_index_dirty |= BM_LOOP;
- /* adding new faces as we loop over faces
- * is normally best avoided, however in this case its not so bad because any face touched twice
- * will already be triangulated*/
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (f->len == 4) {
- BMLoop *f_l[4];
- BMLoop *l_a, *l_b;
+ {
+ MemArena *pf_arena;
+ Heap *pf_heap;
+ EdgeHash *pf_ehash;
- {
- BMLoop *l_iter = BM_FACE_FIRST_LOOP(f);
+ LinkNode *faces_double = NULL;
- f_l[0] = l_iter; l_iter = l_iter->next;
- f_l[1] = l_iter; l_iter = l_iter->next;
- f_l[2] = l_iter; l_iter = l_iter->next;
- f_l[3] = l_iter;
- }
+ if (has_ngon) {
+ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+ else {
+ pf_arena = NULL;
+ pf_heap = NULL;
+ pf_ehash = NULL;
+ }
- if (len_squared_v3v3(f_l[0]->v->co, f_l[2]->v->co) <
- len_squared_v3v3(f_l[1]->v->co, f_l[3]->v->co))
- {
- l_a = f_l[0];
- l_b = f_l[2];
+ /* adding new faces as we loop over faces
+ * is normally best avoided, however in this case its not so bad because any face touched twice
+ * will already be triangulated*/
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (f->len > 3) {
+ has_cut |= bm_face_triangulate(
+ bm, f, &faces_double,
+ r_edges_tri_tot,
+
+ pf_arena,
+ pf_heap, pf_ehash);
}
- else {
- l_a = f_l[1];
- l_b = f_l[3];
- }
-
-#ifdef USE_SAFETY_CHECKS
- if (BM_edge_exists(l_a->v, l_b->v) == NULL)
-#endif
- {
- BMFace *f_new;
- BMLoop *l_new;
-
- /* warning, NO_DOUBLE option here isn't handled as nice as it could be
- * - if there is a quad that has a free standing edge joining it along
- * where we want to split the face, there isnt a good way we can handle this.
- * currently that edge will get removed when joining the tris back into a quad. */
- f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
-
- if (f_new) {
- /* the value of this doesn't matter, only that the 2 loops match and have unique values */
- const int f_index = BM_elem_index_get(f);
-
- /* since we just split theres only ever 2 loops */
- BLI_assert(BM_edge_is_manifold(l_new->e));
-
- BM_elem_index_set(l_new, f_index); /* set_dirty */
- BM_elem_index_set(l_new->radial_next, f_index); /* set_dirty */
+ }
- BM_face_normal_update(f);
- BM_face_normal_update(f_new);
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
- has_cut = true;
- }
- }
+ if (has_ngon) {
+ BLI_memarena_free(pf_arena);
+ BLI_heap_free(pf_heap, NULL);
+ BLI_edgehash_free(pf_ehash, NULL);
}
- }
- BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
- if (has_cut) {
- /* now triangulation is done we need to correct index values */
- BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
+ if (has_cut) {
+ /* now triangulation is done we need to correct index values */
+ BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
+ }
}
return has_cut;
}
-static void bm_decim_triangulate_end(BMesh *bm)
+
+static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
{
/* decimation finished, now re-join */
BMIter iter;
- BMEdge *e, *e_next;
+ BMEdge *e;
+
+ /* we need to collect before merging for ngons since the loops indices will be lost */
+ BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__);
+ STACK_DECLARE(edges_tri);
+
+ STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge));
/* boundary edges */
- BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(e, &l_a, &l_b)) {
const int l_a_index = BM_elem_index_get(l_a);
if (l_a_index != -1) {
const int l_b_index = BM_elem_index_get(l_b);
if (l_a_index == l_b_index) {
- if (LIKELY(l_a->f->len == 3 && l_b->f->len == 3)) {
- if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
- /* check we are not making a degenerate quad */
+ if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
+ /* check we are not making a degenerate quad */
+
+#define CAN_LOOP_MERGE(l) \
+ (BM_loop_is_manifold(l) && \
+ ((l)->v != (l)->radial_next->v) && \
+ (l_a_index == BM_elem_index_get(l)) && \
+ (l_a_index == BM_elem_index_get((l)->radial_next)))
+
+ if ((l_a->f->len == 3 && l_b->f->len == 3) &&
+ (!CAN_LOOP_MERGE(l_a->next)) &&
+ (!CAN_LOOP_MERGE(l_a->prev)) &&
+ (!CAN_LOOP_MERGE(l_b->next)) &&
+ (!CAN_LOOP_MERGE(l_b->prev)))
+ {
BMVert *vquad[4] = {
e->v1,
BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
@@ -596,17 +668,32 @@ static void bm_decim_triangulate_end(BMesh *bm)
BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
- if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
- /* highly unlikely to fail, but prevents possible double-ups */
- BMFace *f[2] = {l_a->f, l_b->f};
- BM_faces_join(bm, f, 2, true);
+ if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
+ continue;
}
}
+#undef CAN_LOOP_MERGE
+
+ /* highly unlikely to fail, but prevents possible double-ups */
+ STACK_PUSH(edges_tri, e);
}
}
}
}
}
+
+ for (int i = 0; i < STACK_SIZE(edges_tri); i++) {
+ BMLoop *l_a, *l_b;
+ e = edges_tri[i];
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ BMFace *f_array[2] = {l_a->f, l_b->f};
+ BM_faces_join(bm, f_array, 2, false);
+ if (e->l == NULL) {
+ BM_edge_kill(bm, e);
+ }
+ }
+ }
+ MEM_freeN(edges_tri);
}
#endif /* USE_TRIANGULATE */
@@ -1083,7 +1170,7 @@ static bool bm_decim_edge_collapse(
return false;
}
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
/* check if this would result in an overlapping face */
if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
@@ -1205,7 +1292,8 @@ static bool bm_decim_edge_collapse(
* \param factor face count multiplier [0 - 1]
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
- * \param axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
*/
void BM_mesh_decimate_collapse(
BMesh *bm,
@@ -1219,7 +1307,6 @@ void BM_mesh_decimate_collapse(
Quadric *vquadrics; /* vert index aligned quadrics */
int tot_edge_orig;
int face_tot_target;
- bool use_triangulate;
CD_UseFlag customdata_flag = 0;
@@ -1229,8 +1316,11 @@ void BM_mesh_decimate_collapse(
#endif
#ifdef USE_TRIANGULATE
+ int edges_tri_tot = 0;
/* temp convert quads to triangles */
- use_triangulate = bm_decim_triangulate_begin(bm);
+ bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot);
+#else
+ UNUSED_VARS(do_triangulate);
#endif
@@ -1352,7 +1442,7 @@ void BM_mesh_decimate_collapse(
goto invalidate;
}
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
if (e_index_mirr == e_index) {
optimize_co[symmetry_axis] = 0.0f;
@@ -1415,7 +1505,7 @@ invalidate:
/* its possible we only had triangles, skip this step in that case */
if (LIKELY(use_triangulate)) {
/* temp convert quads to triangles */
- bm_decim_triangulate_end(bm);
+ bm_decim_triangulate_end(bm, edges_tri_tot);
}
}
#endif
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/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 9d1f7fa45d2..58234ddf3bd 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -53,6 +53,8 @@
#include "BLI_buffer.h"
#include "bmesh.h"
+#include "intern/bmesh_private.h"
+
#include "bmesh_intersect.h" /* own include */
#include "tools/bmesh_edgesplit.h"
@@ -535,8 +537,6 @@ static void bm_isect_tri_tri(
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
float f_a_nor[3];
float f_b_nor[3];
- int a_mask = 0;
- int b_mask = 0;
unsigned int i;
@@ -556,6 +556,22 @@ static void bm_isect_tri_tri(
STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
+#define VERT_VISIT_A _FLAG_WALK
+#define VERT_VISIT_B _FLAG_WALK_ALT
+
+#define STACK_PUSH_TEST_A(ele) \
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \
+ STACK_PUSH(iv_ls_a, ele); \
+ } ((void)0)
+
+#define STACK_PUSH_TEST_B(ele) \
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \
+ STACK_PUSH(iv_ls_b, ele); \
+ } ((void)0)
+
+
/* vert-vert
* --------- */
{
@@ -567,22 +583,18 @@ static void bm_isect_tri_tri(
unsigned int i_b;
for (i_b = 0; i_b < 3; i_b++) {
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- if (!((1 << i_a) & a_mask)) {
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
- a_mask |= (1 << i_a);
#ifdef USE_DUMP
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) {
printf(" ('VERT-VERT-A') %d, %d),\n",
i_a, BM_elem_index_get(fv_a[i_a]));
-#endif
}
- if (!((1 << i_b) & b_mask)) {
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
-#ifdef USE_DUMP
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) {
printf(" ('VERT-VERT-B') %d, %d),\n",
i_b, BM_elem_index_get(fv_b[i_b]));
-#endif
}
+#endif
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
}
}
}
@@ -593,22 +605,25 @@ static void bm_isect_tri_tri(
{
unsigned int i_a;
for (i_a = 0; i_a < 3; i_a++) {
- if (!((1 << i_a) & a_mask)) {
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
unsigned int i_b_e0;
for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
- float fac;
- if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
+ {
continue;
- fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
+ }
+
+ const float fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
- // STACK_PUSH(iv_ls_a, fv_a[i_a]);
- a_mask |= (1 << i_a);
+ STACK_PUSH_TEST_B(fv_a[i_a]);
+ // STACK_PUSH_TEST_A(fv_a[i_a]);
e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
#ifdef USE_DUMP
printf(" ('VERT-EDGE-A', %d, %d),\n",
@@ -631,22 +646,25 @@ static void bm_isect_tri_tri(
{
unsigned int i_b;
for (i_b = 0; i_b < 3; i_b++) {
- if (!((1 << i_b) & b_mask)) {
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
unsigned int i_a_e0;
for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
- float fac;
- if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
+ {
continue;
- fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
+ }
+
+ const float fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- // STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
#ifdef USE_DUMP
printf(" ('VERT-EDGE-B', %d, %d),\n",
@@ -680,17 +698,15 @@ static void bm_isect_tri_tri(
// second check for verts intersecting the triangle
for (i_a = 0; i_a < 3; i_a++) {
- float ix[3];
- if ((1 << i_a) & a_mask)
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) {
continue;
+ }
+
+ float ix[3];
if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1);
- BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
- a_mask |= (1 << i_a);
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_a[i_a]);
#ifdef USE_DUMP
printf(" 'VERT TRI-A',\n");
#endif
@@ -709,18 +725,15 @@ static void bm_isect_tri_tri(
tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
for (i_b = 0; i_b < 3; i_b++) {
- float ix[3];
- if ((1 << i_b) & b_mask)
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) {
continue;
+ }
+ float ix[3];
if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
#ifdef USE_DUMP
printf(" 'VERT TRI-B',\n");
#endif
@@ -735,7 +748,7 @@ static void bm_isect_tri_tri(
#ifdef USE_DUMP
printf("# OVERLAP\n");
#endif
- return;
+ goto finally;
}
normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
@@ -744,37 +757,42 @@ static void bm_isect_tri_tri(
/* edge-tri & edge-edge
* -------------------- */
{
- unsigned int i_e0;
- for (i_e0 = 0; i_e0 < 3; i_e0++) {
- unsigned int i_e1 = (i_e0 + 1) % 3;
+ for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
- if (((1 << i_e0) | (1 << i_e1)) & a_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
+ {
continue;
- iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
+ }
+
+ iv = bm_isect_edge_tri(s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
if (iv) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
printf(" ('EDGE-TRI-A', %d),\n", side);
#endif
}
}
- for (i_e0 = 0; i_e0 < 3; i_e0++) {
- unsigned int i_e1 = (i_e0 + 1) % 3;
+ for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
- if (((1 << i_e0) | (1 << i_e1)) & b_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
+ {
continue;
- iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
+ }
+
+ iv = bm_isect_edge_tri(s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
if (iv) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
printf(" ('EDGE-TRI-B', %d),\n", side);
#endif
@@ -827,6 +845,15 @@ static void bm_isect_tri_tri(
// BLI_assert(len(ie_vs) <= 2)
}
}
+
+finally:
+ for (i = 0; i < STACK_SIZE(iv_ls_a); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A); \
+ }
+ for (i = 0; i < STACK_SIZE(iv_ls_b); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B); \
+ }
+
}
#ifdef USE_BVH
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 3adddddb8e7..6ff6de33d56 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -172,8 +172,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
}
}
-VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata){
-}
+VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) {}
void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
{
@@ -271,38 +270,41 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
const std::string &name = bc_get_dae_name(mesh);
- int hole_count = 0;
for (unsigned i = 0; i < prim_arr.getCount(); i++) {
-
+
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
const char *type_str = bc_primTypeToStr(type);
-
+
// OpenCollada passes POLYGONS type for <polylist>
if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
-
+
+ int hole_count = 0;
+ int nonface_count = 0;
+
for (unsigned int j = 0; j < vca.getCount(); j++) {
int count = vca[j];
if (abs(count) < 3) {
- fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n",
- type_str, name.c_str());
- return false;
+ nonface_count++;
}
- if (count < 0)
- {
+
+ if (count < 0) {
hole_count ++;
}
}
- if (hole_count > 0)
- {
+ if (hole_count > 0) {
fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count);
}
+
+ if (nonface_count > 0) {
+ fprintf(stderr, "WARNING: Primitive %s in %s: %d faces with vertex count < 3 (rejected)\n", type_str, name.c_str(), nonface_count);
+ }
}
else if (type == COLLADAFW::MeshPrimitive::LINES) {
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/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 624378f2ae9..7d59358831c 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -160,10 +160,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
int ix = x, iy = y;
- if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
zero_v4(output);
}
- else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
+ else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
zero_v4(output);
}
else {
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 220b4e908a6..d6e5fdf86bb 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -94,7 +94,7 @@ void MaskOperation::initExecution()
frame_iter += frame_step;
}
- BKE_mask_free_nolib(mask_temp);
+ BKE_mask_free(mask_temp);
MEM_freeN(mask_temp);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 9f80c21a6a4..6169100d574 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/build/deg_builder.cc
+/** \file blender/depsgraph/intern/builder/deg_builder.cc
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 7ecb4b20684..bdc030e3810 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/build/deg_builder.h
+/** \file blender/depsgraph/intern/builder/deg_builder.h
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 5359cc8754a..74a5be997f1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
@@ -296,16 +296,15 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
- /* object itself */
- build_object(scene, base, ob);
-
/* object that this is a proxy for */
// XXX: the way that proxies work needs to be completely reviewed!
if (ob->proxy) {
ob->proxy->proxy_from = ob;
- build_object(scene, base, ob->proxy);
}
+ /* object itself */
+ build_object(scene, base, ob);
+
/* Object dupligroup. */
if (ob->dup_group) {
build_group(scene, base, ob->dup_group);
@@ -486,6 +485,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
if (ob->gpd) {
build_gpencil(ob->gpd);
}
+
+ if (ob->proxy != NULL) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST,
+ function_bind(BKE_object_eval_proxy_backlink, _1, ob),
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 0e78df52ff8..f870a33fb68 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 10aebb75fbf..34c661b21f3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -266,6 +266,13 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
+ /* Object that this is a proxy for.
+ * Just makes sure backlink is correct.
+ */
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+
/* object itself */
build_object(bmain, scene, ob);
@@ -433,7 +440,6 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
break;
}
-
case OB_ARMATURE: /* Pose */
if (ob->id.lib != NULL && ob->proxy_from != NULL) {
build_proxy_rig(ob);
@@ -1069,7 +1075,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
/* XXX: if particle system is later re-enabled, we must do full rebuild? */
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
/* TODO(sergey): Are all particle systems depends on time?
@@ -1311,10 +1317,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
}
+ else {
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ }
parchan->flag |= POSE_DONE;
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
root_map->add_bone(parchan->name, rootchan->name);
@@ -1426,20 +1434,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/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index c0bf82becda..ce6d2c961fd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -42,7 +42,6 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
-#include "intern/depsgraph_types.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_operation.h"
@@ -292,7 +291,8 @@ struct DepsNodeHandle
/* Utilities for Builders ----------------------------------------------------- */
template <typename KeyType>
-OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) {
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
+{
DepsNode *node = find_node(key);
return node != NULL ? node->get_exit_operation() : NULL;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 0322ef7fa1d..76cd81f1b8f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -99,7 +99,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
/* Remove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
- )
+ )
{
DepsRelation *rel = *it_rel;
/* Increment in advance, so we can safely remove the relation. */
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 97208939e57..4ce91516c84 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -136,13 +136,15 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
return "UNKNOWN";
}
-DepsOperationStringifier::DepsOperationStringifier() {
+DepsOperationStringifier::DepsOperationStringifier()
+{
for (int i = 0; i < DEG_NUM_OPCODES; ++i) {
names_[i] = stringify_opcode((eDepsOperation_Code)i);
}
}
-const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) {
+const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
+{
BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
return names_[opcode];
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 198cd349002..3024d625846 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_eval.cc
+/** \file blender/depsgraph/intern/eval/deg_eval.cc
* \ingroup depsgraph
*
* Evaluation engine entrypoints for Depsgraph Engine.
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index 0d42f63433f..92f87b03803 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/eval/deg_eval.cc
+/** \file blender/depsgraph/intern/eval/deg_eval.h
* \ingroup depsgraph
*
* Evaluation engine entrypoints for Depsgraph Engine.
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index af68f5c55c4..9ba0b61a4f1 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_tag.cc
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc
* \ingroup depsgraph
*
* Core routines for how the Depsgraph works.
@@ -80,10 +80,14 @@ static void flush_init_func(void *data_v, int i)
*/
Depsgraph *graph = (Depsgraph *)data_v;
OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
+ ComponentDepsNode *comp_node = node->owner;
+ IDDepsNode *id_node = comp_node->owner;
id_node->done = 0;
+ comp_node->done = 0;
node->scheduled = false;
- node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
+ if (comp_node->type == DEPSNODE_TYPE_PROXY) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
}
/* Flush updates from tagged nodes outwards until all affected nodes
@@ -133,49 +137,10 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
for (;;) {
node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- IDDepsNode *id_node = node->owner->owner;
-
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
-
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- ID *id = id_node->id;
- /* This code is used to preserve those areas which does direct
- * object update,
- *
- * Plus it ensures visibility changes and relations and layers
- * visibility update has proper flags to work with.
- */
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- ComponentDepsNode *comp_node = node->owner;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
-
- /* TODO(sergey): For until incremental updates are possible
- * witin a component at least we tag the whole component
- * for update.
- */
- ComponentDepsNode *component = node->owner;
- if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
- foreach (OperationDepsNode *op, component->operations) {
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- component->flags |= DEPSCOMP_FULLY_SCHEDULED;
- }
+ ComponentDepsNode *comp_node = node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ id_node->done = 1;
+ comp_node->done = 1;
/* Flush to nodes along links... */
if (node->outlinks.size() == 1) {
@@ -200,6 +165,52 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
}
}
}
+
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
+ {
+ if (id_node->done == 1) {
+ ID *id = id_node->id;
+ Object *object = NULL;
+
+ if (GS(id->name) == ID_OB) {
+ object = (Object *)id;
+ }
+
+ deg_editors_id_update(bmain, id_node->id);
+
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components)
+ {
+ if (comp_node->done) {
+ foreach (OperationDepsNode *op, comp_node->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ if (object != NULL) {
+ /* This code is used to preserve those areas which does
+ * direct object update,
+ *
+ * Plus it ensures visibility changes and relations and
+ * layers visibility update has proper flags to work with.
+ */
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+ }
+ GHASH_FOREACH_END();
}
static void graph_clear_func(void *data_v, int i)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index 8912aebee7d..ecd3a5ec660 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.h
* \ingroup depsgraph
*
* Core routines for how the Depsgraph works.
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 78293f7f483..12d5ee00a63 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode.cc
+/** \file blender/depsgraph/intern/nodes/deg_node.cc
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index d79d3d2348d..416996052c9 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode.h
+/** \file depsgraph/intern/nodes/deg_node.h
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 7e49fec051f..6ac45c99798 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_component.cc
+/** \file blender/depsgraph/intern/nodes/deg_node_component.cc
* \ingroup depsgraph
*/
@@ -86,7 +86,6 @@ static void comp_node_hash_value_free(void *value_v)
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL),
- flags(0),
layers(0)
{
operations_map = BLI_ghash_new(comp_node_hash_key,
@@ -117,10 +116,10 @@ string ComponentDepsNode::identifier() const
{
string &idname = this->owner->name;
- char typebuf[7];
+ char typebuf[16];
sprintf(typebuf, "(%d)", type);
- char layers[7];
+ char layers[16];
sprintf(layers, "%d", this->layers);
return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
@@ -257,7 +256,7 @@ OperationDepsNode *ComponentDepsNode::get_entry_operation()
entry_operation = op_node;
return op_node;
}
- else if(operations.size() == 1) {
+ else if (operations.size() == 1) {
return operations[0];
}
return NULL;
@@ -280,7 +279,7 @@ OperationDepsNode *ComponentDepsNode::get_exit_operation()
exit_operation = op_node;
return op_node;
}
- else if(operations.size() == 1) {
+ else if (operations.size() == 1) {
return operations[0];
}
return NULL;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index df321ea9299..6f62d91cd79 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_component.h
+/** \file blender/depsgraph/intern/nodes/deg_node_component.h
* \ingroup depsgraph
*/
@@ -47,13 +47,6 @@ struct Depsgraph;
struct OperationDepsNode;
struct BoneComponentDepsNode;
-typedef enum eDepsComponent_Flag {
- /* Temporary flags, meaning all the component's operations has been
- * scheduled for update.
- */
- DEPSCOMP_FULLY_SCHEDULED = 1,
-} eDepsComponent_Flag;
-
/* ID Component - Base type for all components */
struct ComponentDepsNode : public DepsNode {
/* Key used to look up operations within a component */
@@ -165,8 +158,6 @@ struct ComponentDepsNode : public DepsNode {
// XXX: a poll() callback to check if component's first node can be started?
- int flags;
-
/* Temporary bitmask, used during graph construction. */
int layers;
};
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index a9f9703bb3b..5847af29ac2 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_operation.cc
+/** \file blender/depsgraph/intern/nodes/deg_node_operation.cc
* \ingroup depsgraph
*/
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index f03078fc3db..598393054db 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_operation.h
+/** \file blender/depsgraph/intern/nodes/deg_node_operation.h
* \ingroup depsgraph
*/
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 8822c8511de..c98470fb194 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2119,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_animdata_free(id);
+ BKE_animdata_free(id, true);
}
}
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index ae6894ac546..fc6f4036d02 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -192,7 +192,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define HSV_BANDWIDTH 0.3f
/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
-//void fcurve_rainbow (unsigned int cur, unsigned int tot, float *out)
+// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
{
float hsv[3], fac;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index a82cca9e52a..21c25f829b1 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -158,7 +158,7 @@ static int add_driver_with_target(
ReportList *UNUSED(reports),
ID *dst_id, const char dst_path[], int dst_index,
ID *src_id, const char src_path[], int src_index,
- PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *dst_ptr, PropertyRNA *dst_prop,
PointerRNA *src_ptr, PropertyRNA *src_prop,
short flag, int driver_type)
{
@@ -207,11 +207,15 @@ static int add_driver_with_target(
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
* (The only issue is with quat rotations vs euler channels...)
+ * - To avoid problems with transform properties depending on the final transform that they
+ * control (thus creating pseudo-cycles - see T48734), we don't use transform channels
+ * when both the source and destinations are in same places.
*/
dvar = driver_add_new_variable(driver);
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
- (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
+ (src_ptr->data != dst_ptr->data))
{
/* Transform Channel */
DriverTarget *dtar;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 08a7355694b..7b35a154fc8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
}
/**
- * only called from #ok_bezier_region_lasso
+ * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
*/
-static bool bezier_region_lasso_test(
- const struct KeyframeEdit_LassoData *data_lasso,
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
+ if (ked->data) {
+ KeyframeEdit_LassoData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_lasso_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
/**
- * only called from #ok_bezier_region_circle
+ * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
*/
-static bool bezier_region_circle_test(
- const struct KeyframeEdit_CircleData *data_circle,
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
+ if (ked->data) {
+ KeyframeEdit_CircleData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_circle_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region_lasso;
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
+ case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
+ return ok_bezier_channel_lasso;
+ case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
+ return ok_bezier_channel_circle;
default: /* nothing was ok */
return NULL;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 172f2b9069e..0c0f54f0179 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
+ else if (RNA_property_subtype(prop), PROP_QUATERNION) {
+ fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
+ }
}
/* insert keyframe */
@@ -2035,7 +2038,7 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
else {
/* Normal Mode (or treat as being normal mode):
*
- * Just in case the flags are't set properly (i.e. only on/off is set, without a mode)
+ * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
* let's set the "normal" flag too, so that it will all be sane everywhere...
*/
scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index ebdf6bb43ff..2f5b2ab6e87 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editcurve_paint.c
editcurve_select.c
editfont.c
+ editfont_undo.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index bb7cc61f580..38018541929 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -911,7 +911,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int corners_index_len = 0;
const int result = curve_fit_cubic_to_points_fl(
- coords, stroke_len, dims, error_threshold,
+ coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY,
corners, corners_len,
&cubic_spline, &cubic_spline_len,
NULL,
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 7c1fe0cadf0..053a7ee5023 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1794,64 +1794,6 @@ void FONT_OT_unlink(wmOperatorType *ot)
ot->exec = font_unlink_exec;
}
-
-/* **************** undo for font object ************** */
-
-static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- const char *str = strv;
-
- ef->pos = *((const short *)str);
- ef->len = *((const short *)(str + 2));
-
- memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t));
- memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo));
-
- ef->selstart = ef->selend = 0;
-
-}
-
-static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- char *str;
-
- /* The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo */
- str = MEM_callocN((MAXTEXT + 6) * sizeof(wchar_t) + (MAXTEXT + 4) * sizeof(CharInfo), "string undo");
-
- /* Copy the string and string information */
- memcpy(str + 4, ef->textbuf, (ef->len + 1) * sizeof(wchar_t));
- memcpy(str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->textbufinfo, ef->len * sizeof(CharInfo));
-
- *((short *)(str + 0)) = ef->pos;
- *((short *)(str + 2)) = ef->len;
-
- return str;
-}
-
-static void free_undoFont(void *strv)
-{
- MEM_freeN(strv);
-}
-
-static void *get_undoFont(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_FONT) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_font(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
-}
-
/**
* TextBox selection
*/
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
new file mode 100644
index 00000000000..a0453f9694d
--- /dev/null
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -0,0 +1,311 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editfont_undo.c
+ * \ingroup edcurve
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_font.h"
+
+#include "ED_curve.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+# include "BLI_array_store.h"
+# include "BLI_array_store_utils.h"
+# include "BLI_listbase.h"
+# define ARRAY_CHUNK_SIZE 32
+#endif
+
+typedef struct UndoFont {
+ wchar_t *textbuf;
+ struct CharInfo *textbufinfo;
+
+ int len, pos;
+
+#ifdef USE_ARRAY_STORE
+ struct {
+ BArrayState *textbuf;
+ BArrayState *textbufinfo;
+ } store;
+#endif
+} UndoFont;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ struct BArrayStore_AtSize bs_stride;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+} uf_arraystore = {NULL};
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void uf_arraystore_compact_ex(
+ UndoFont *uf, const UndoFont *uf_ref,
+ bool create)
+{
+#define STATE_COMPACT(uf, id, len) \
+ if ((uf)->id) { \
+ BLI_assert(create == ((uf)->store.id == NULL)); \
+ if (create) { \
+ BArrayState *state_reference = uf_ref ? uf_ref->store.id : NULL; \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&uf_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); \
+ (uf)->store.id = BLI_array_store_state_add( \
+ bs, (uf)->id, (size_t)(len) * stride, state_reference); \
+ } \
+ /* keep uf->len for validation */ \
+ MEM_freeN((uf)->id); \
+ (uf)->id = NULL; \
+ } ((void)0)
+
+ STATE_COMPACT(uf, textbuf, uf->len + 1);
+ STATE_COMPACT(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_COMPACT
+
+ if (create) {
+ uf_arraystore.users += 1;
+ }
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void uf_arraystore_compact(UndoFont *um, const UndoFont *uf_ref)
+{
+ uf_arraystore_compact_ex(um, uf_ref, true);
+}
+
+static void uf_arraystore_compact_with_info(UndoFont *um, const UndoFont *uf_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
+#endif
+
+ uf_arraystore_compact(um, uf_ref);
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void uf_arraystore_expand_clear(UndoFont *um)
+{
+ uf_arraystore_compact_ex(um, NULL, false);
+}
+
+static void uf_arraystore_expand(UndoFont *uf)
+{
+#define STATE_EXPAND(uf, id, len) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayState *state = (uf)->store.id; \
+ size_t state_len; \
+ (uf)->id = BLI_array_store_state_data_get_alloc(state, &state_len); \
+ BLI_assert((len) == (state_len / stride)); \
+ UNUSED_VARS_NDEBUG(stride); \
+ } ((void)0)
+
+ STATE_EXPAND(uf, textbuf, uf->len + 1);
+ STATE_EXPAND(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_EXPAND
+}
+
+static void uf_arraystore_free(UndoFont *uf)
+{
+#define STATE_FREE(uf, id) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_get(&uf_arraystore.bs_stride, stride); \
+ BArrayState *state = (uf)->store.id; \
+ BLI_array_store_state_remove(bs, state); \
+ (uf)->store.id = NULL; \
+ } ((void)0)
+
+ STATE_FREE(uf, textbuf);
+ STATE_FREE(uf, textbufinfo);
+
+#undef STATE_FREE
+
+ uf_arraystore.users -= 1;
+
+ BLI_assert(uf_arraystore.users >= 0);
+
+ if (uf_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("editfont undo store: freeing all data!\n");
+#endif
+
+ BLI_array_store_at_size_clear(&uf_arraystore.bs_stride);
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+ const UndoFont *uf = uf_v;
+
+ size_t final_size;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand(uf_v);
+#endif
+
+ final_size = sizeof(wchar_t) * (uf->len + 1);
+ memcpy(ef->textbuf, uf->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (uf->len + 1);
+ memcpy(ef->textbufinfo, uf->textbufinfo, final_size);
+
+ ef->pos = uf->pos;
+ ef->len = uf->len;
+
+ ef->selstart = ef->selend = 0;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand_clear(uf_v);
+#endif
+}
+
+static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+
+ UndoFont *uf = MEM_callocN(sizeof(*uf), __func__);
+
+ size_t final_size;
+
+ final_size = sizeof(wchar_t) * (ef->len + 1);
+ uf->textbuf = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbuf, ef->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (ef->len + 1);
+ uf->textbufinfo = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbufinfo, ef->textbufinfo, final_size);
+
+ uf->pos = ef->pos;
+ uf->len = ef->len;
+
+#ifdef USE_ARRAY_STORE
+ {
+ const UndoFont *uf_ref = uf_arraystore.local_links.last ?
+ ((LinkData *)uf_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&uf_arraystore.local_links, BLI_genericNodeN(uf));
+
+ uf_arraystore_compact_with_info(uf, uf_ref);
+ }
+#endif
+
+ return uf;
+}
+
+static void free_undoFont(void *uf_v)
+{
+ UndoFont *uf = uf_v;
+
+#ifdef USE_ARRAY_STORE
+ {
+ LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data));
+ BLI_remlink(&uf_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ uf_arraystore_free(uf);
+#endif
+
+ if (uf->textbuf) {
+ MEM_freeN(uf->textbuf);
+ }
+ if (uf->textbufinfo) {
+ MEM_freeN(uf->textbufinfo);
+ }
+
+ MEM_freeN(uf);
+}
+
+static void *get_undoFont(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_FONT) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_font(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 0329598d711..79a2c494239 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -763,6 +763,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
}
glEnd();
+ glShadeModel(GL_SMOOTH);
}
/* draw debug points of curve on top? (original stroke points) */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a49b3362155..738496a67c6 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index bd1697b9a54..ac49a51c716 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
/* identifiers */
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil datablock";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+/* **************** Delete All Active Frames ****************** */
+
+static int gp_actframe_delete_all_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
+}
+
+static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool success = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
+}
+
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index dd28f6ac531..53fb33eeb9b 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 405b673c42b..65ee1122b56 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Delete Active Frame - For easier video tutorials/review sessions */
/* NOTE: This works even when not in EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
@@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index fba2f30e715..a570d586f50 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result {
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
@@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval, pc1) <= radius) {
- /* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ // XXX: pressure sensitive eraser should apply here too?
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
}
}
}
@@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get coordinates of point in screenspace */
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
@@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p)
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
@@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
@@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
- ToolSettings *ts = p->scene->toolsettings;
short add_frame_mode;
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
diff --git a/source/blender/editors/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/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0ac5c17a552..d3d2c465d46 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -94,6 +94,7 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment
* The param must cause only one value to be gotten from GL.
*/
float glaGetOneFloat(int param);
+int glaGetOneInt(int param);
/**
* Functions like glRasterPos2i, except ensures that the resulting
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index fb4897c6532..27e1051a336 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -608,7 +608,7 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_SKIPKNOTS = (1 << 4),
/* Scale FCurve i a way it fits to -1..1 space */
ANIM_UNITCONV_NORMALIZE = (1 << 5),
- /* Only whennormalization is used: use scale factor from previous run,
+ /* Only when normalization is used: use scale factor from previous run,
* prevents curves from jumping all over the place when tweaking them.
*/
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 9a987d7618c..64c16605dec 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
-void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
-
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 278e3f97ba7..859d45e9c86 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -72,8 +72,7 @@ void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
-/* editfont.h */
-void undo_push_font(struct bContext *C, const char *name);
+/* editfont.c */
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
@@ -89,6 +88,9 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]);
bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/* editfont_undo.c */
+void undo_push_font(struct bContext *C, const char *name);
+
#if 0
/* debug only */
void printknots(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 186a2a26825..92acfa6c1d2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -104,11 +104,12 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct
void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
-int ED_file_extension_icon(const char *relname);
+int ED_path_extension_type(const char *path);
+int ED_file_extension_icon(const char *path);
void ED_file_read_bookmarks(void);
-void ED_file_change_dir(struct bContext *C, const bool checkdir);
+void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 255827db373..de5ab80a88f 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -42,6 +42,7 @@ struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct bAnimContext;
+struct KeyframeEditData;
struct PointerRNA;
struct wmWindowManager;
struct wmKeyConfig;
@@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index fae3e3677a0..c0eb88cd982 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -45,14 +45,21 @@ struct Scene;
/* bezt validation */
typedef enum eEditKeyframes_Validate {
+ /* Frame range */
BEZT_OK_FRAME = 1,
BEZT_OK_FRAMERANGE,
+ /* Selection status */
BEZT_OK_SELECTED,
+ /* Values (y-val) only */
BEZT_OK_VALUE,
BEZT_OK_VALUERANGE,
+ /* For graph editor keyframes (2D tests) */
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
BEZT_OK_REGION_CIRCLE,
+ /* Only for keyframes a certain Dopesheet channel */
+ BEZT_OK_CHANNEL_LASSO,
+ BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
-struct KeyframeEdit_LassoData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_LassoData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
const int (*mcords)[2];
int mcords_tot;
-};
+} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
-struct KeyframeEdit_CircleData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_CircleData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
float mval[2];
float radius_squared;
-};
+} KeyframeEdit_CircleData;
/* ************************************************ */
@@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
/* current iteration data */
struct FCurve *fcu; /* F-Curve that is being iterated over */
int curIndex; /* index of current keyframe being iterated over */
-
+ float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
+
/* flags */
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
eKeyframeIterFlags iterflags; /* settings for iteration process */
@@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
+/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
+/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
+
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
+ const float xy[2]);
+
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
+ const float xy[2]);
+
+
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 1f13b46ff2a..2ab788d5e2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -35,6 +35,7 @@ struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
+struct KeyframeEditData;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 7fe9a0c320c..f7b9d6b4f9e 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
-void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
-
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index af4af8e2f5d..73ee2542247 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,10 +27,4 @@
#ifndef __ED_OUTLINER_H__
#define __ED_OUTLINER_H__
-struct ID;
-struct SpaceOops;
-
-/* Used to check whether a given texture context is valid in current context. */
-void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
-
#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h
index 584e9a92bb6..fed842c969e 100644
--- a/source/blender/editors/include/ED_physics.h
+++ b/source/blender/editors/include/ED_physics.h
@@ -45,12 +45,12 @@ int PE_hair_poll(struct bContext *C);
int PE_poll_view3d(struct bContext *C);
/* rigidbody_object.c */
-bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* rigidbody_constraint.c */
-bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* operators */
void ED_operatortypes_physics(void);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index baf4ed574cf..7944b434057 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -75,7 +75,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
struct Main *bmain, struct Scene *scene, int flag,
/* extra args for view3d */
- struct ARegion *ar, struct View3D *v3d);
+ const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
/* callbacks to filter how snap works */
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f143ea478c6..b6b80b93e0b 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C);
bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
-void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
void ED_OT_flush_edits(struct wmOperatorType *ot);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 54b4acec864..8bd8a14030f 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -208,10 +208,12 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
-bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float ray_start[3], float ray_normal[3], const bool do_clip);
-bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
+bool ED_view3d_win_to_ray(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float ray_start[3], float ray_normal[3], const bool do_clip);
+bool ED_view3d_win_to_ray_ex(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]);
@@ -403,4 +405,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View
#define V3D_IS_ZBUF(v3d) \
(((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9aad340d2fb..a623f5cfb9c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+void UI_context_active_but_prop_get(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
-void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(
+ struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index fac1267cc62..ba7240be5d8 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2576,9 +2576,11 @@ static void ui_set_but_soft_range(uiBut *but)
}
else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
float value = ui_but_value_get(but);
- CLAMP(value, but->hardmin, but->hardmax);
- but->softmin = min_ff(but->softmin, value);
- but->softmax = max_ff(but->softmax, value);
+ if (isfinite(value)) {
+ CLAMP(value, but->hardmin, but->hardmax);
+ but->softmin = min_ff(but->softmin, value);
+ but->softmax = max_ff(but->softmax, value);
+ }
}
else {
BLI_assert(0);
@@ -4323,7 +4325,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
/**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 8fbc545cb77..72a6a04feec 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -181,7 +181,6 @@ void UI_draw_roundbox_shade_x(
coldown[1] = max_ff(0.0f, color[1] + shadedown);
coldown[2] = max_ff(0.0f, color[2] + shadedown);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -260,7 +259,6 @@ void UI_draw_roundbox_shade_x(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* linear vertical shade within button or in outline */
@@ -291,7 +289,6 @@ void UI_draw_roundbox_shade_y(
colRight[1] = max_ff(0.0f, color[1] + shadeRight);
colRight[2] = max_ff(0.0f, color[2] + shadeRight);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -367,7 +364,6 @@ void UI_draw_roundbox_shade_y(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* plain antialiased unfilled rectangle */
@@ -531,7 +527,6 @@ static void histogram_draw_one(
}
else {
/* under the curve */
- glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
@@ -1087,7 +1082,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* layer: color ramp */
- glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
CBData *cbd = coba->data;
@@ -1133,7 +1127,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
/* layer: box outline */
glColor4f(0.0, 0.0, 0.0, 1.0);
@@ -1212,9 +1205,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ GPU_basic_shader_bind(GPU_basic_shader_bound_options());
gluSphere(qobj, 100.0, 32, 24);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1545,10 +1537,12 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
BLI_rctf_size_x(&rect),
BLI_rctf_size_y(&rect));
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
+
for (int a = 0; a < 2; a++) {
if (a == 1) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
UI_ThemeColor(TH_SEL_MARKER);
}
else {
@@ -1562,9 +1556,10 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
glVertex2f(0.0f, 10.0f);
glEnd();
}
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
- glDisable(GL_LINE_STIPPLE);
glPopMatrix();
ok = true;
@@ -1677,7 +1672,6 @@ static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float s
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
glEnable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
@@ -1689,7 +1683,6 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx,
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_FLAT);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5b8b8ae5bdb..e0b8003d8a9 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6014,20 +6014,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 +6030,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 +6069,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;
}
}
@@ -6981,13 +6981,15 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
!IS_EVENT_MOD(event, shift, oskey) &&
(event->val == KM_PRESS))
{
- if (event->alt)
- ui_but_anim_remove_driver(C);
- else if (event->ctrl)
- ui_but_anim_add_driver(C);
-
- ED_region_tag_redraw(data->region);
-
+ /* quick check to prevent this opening within the popup menu its self */
+ if (!ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
+ if (event->alt)
+ ui_but_anim_remove_driver(C);
+ else if (event->ctrl)
+ ui_but_anim_add_driver(C);
+
+ ED_region_tag_redraw(data->region);
+ }
return WM_UI_HANDLER_BREAK;
}
/* handle keyingsets */
@@ -8011,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
}
/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+void UI_context_active_but_prop_get(
+ const bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
uiBut *activebut = ui_context_rna_button_active(C);
- memset(ptr, 0, sizeof(*ptr));
-
if (activebut && activebut->rnapoin.data) {
- *ptr = activebut->rnapoin;
- *prop = activebut->rnaprop;
- *index = activebut->rnaindex;
+ *r_ptr = activebut->rnapoin;
+ *r_prop = activebut->rnaprop;
+ *r_index = activebut->rnaindex;
}
else {
- *prop = NULL;
- *index = 0;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_index = 0;
}
}
@@ -8436,6 +8439,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
uiListDyn *dyn_data;
int retval = WM_UI_HANDLER_CONTINUE;
int type = event->type, val = event->val;
+ bool redraw = false;
int mx, my;
ui_list = listbox->custom_data;
@@ -8525,7 +8529,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_apply_but_undo(listbox);
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
}
retval = WM_UI_HANDLER_BREAK;
}
@@ -8537,8 +8541,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_list->list_grip += (type == WHEELUPMOUSE) ? -1 : 1;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
@@ -8546,13 +8550,22 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
/* list template will clamp */
ui_list->list_scroll += (type == WHEELUPMOUSE) ? -1 : 1;
- ED_region_tag_redraw(ar);
-
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
}
}
+ if (redraw) {
+ if (listbox->block->flag & UI_BLOCK_POPUP) {
+ /* popups need special refreshing */
+ ED_region_tag_refresh_ui(ar);
+ }
+ else {
+ ED_region_tag_redraw(ar);
+ }
+ }
+
return retval;
}
@@ -9794,11 +9807,28 @@ static int ui_handle_menus_recursive(
}
else {
uiBlock *block = menu->region->uiblocks.first;
+ uiBut *listbox = ui_list_find_mouse_over(menu->region, event);
- if (block->flag & UI_BLOCK_RADIAL)
+ if (block->flag & UI_BLOCK_RADIAL) {
retval = ui_pie_handler(C, event, menu);
- else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
- retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
+ }
+ else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
+ bool handled = false;
+
+ if (listbox) {
+ int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
+ if (retval_test != WM_UI_HANDLER_CONTINUE) {
+ retval = retval_test;
+ handled = true;
+ }
+ }
+
+ if (handled == false) {
+ retval = ui_handle_menu_event(
+ C, event, menu, level,
+ is_parent_inside, is_parent_menu, is_floating);
+ }
+ }
}
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 0a25a8fb3c6..6dc60f1d70b 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -368,7 +368,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
viconutil_set_point(pts[1], cx - d2, cy - d);
viconutil_set_point(pts[2], cx + d2, cy);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -376,7 +375,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -395,13 +393,11 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
glColor4f(0.2f, 0.2f, 0.2f, alpha);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glVertex2iv(pts[0]);
glVertex2iv(pts[1]);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
}
static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
@@ -415,7 +411,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
viconutil_set_point(pts[1], cx - d, cy + d2);
viconutil_set_point(pts[2], cx, cy - d2);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -423,7 +418,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -1220,8 +1214,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
glRasterPos2f(draw_x, draw_y);
glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
if (ima)
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 62b373c58c8..79961eae79d 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1763,12 +1763,10 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
tab_curve_radius, roundboxtype, true, true, NULL);
/* tab highlight (3d look) */
- glShadeModel(GL_SMOOTH);
glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive);
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
tab_curve_radius, roundboxtype, true, false,
is_active ? theme_col_back : theme_col_tab_inactive);
- glShadeModel(GL_FLAT);
}
/* tab blackline */
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 423c48e5f55..8b41302b5bb 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -417,6 +417,11 @@ void uiStyleInit(void)
blf_mono_font = -1;
}
+ if (blf_mono_font_render != -1) {
+ BLF_unload_id(blf_mono_font_render);
+ blf_mono_font_render = -1;
+ }
+
font = U.uifonts.first;
/* default builtin */
@@ -516,7 +521,12 @@ void uiStyleInit(void)
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
- /* second for rendering else we get threading problems */
+ /**
+ * Second for rendering else we get threading problems,
+ *
+ * \note This isn't good that the render font depends on the preferences,
+ * keep for now though, since without this there is no way to display many unicode chars.
+ */
if (blf_mono_font_render == -1)
blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a3b04e1c9bc..7f276bcc634 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -232,15 +232,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
if (!ar)
return;
@@ -251,8 +253,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
template = but->func_argN;
- *ptr = template->ptr;
- *prop = template->prop;
+ *r_ptr = template->ptr;
+ *r_prop = template->prop;
return;
}
}
@@ -2818,7 +2820,7 @@ static void uilist_prepare(
layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len);
}
-static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
+static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiList *ui_list = arg1;
uiListDyn *dyn_data = ui_list->dyn_data;
@@ -2831,6 +2833,9 @@ static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSE
dyn_data->resize_prev += diff * UI_UNIT_Y;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
}
+
+ /* In case uilist is in popup, we need special refreshing */
+ ED_region_tag_refresh_ui(CTX_wm_menu(C));
}
static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 19e0b55374e..5098e701638 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -712,8 +712,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
unsigned char *col_pt = col_array;
shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
-
- glShadeModel(GL_SMOOTH);
+
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
@@ -725,8 +724,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
-
- glShadeModel(GL_FLAT);
}
}
@@ -2311,8 +2308,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
- glShadeModel(GL_SMOOTH);
-
glBegin(GL_TRIANGLE_FAN);
glColor3fv(colcent);
glVertex2f(centx, centy);
@@ -2330,8 +2325,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
}
glEnd();
- glShadeModel(GL_FLAT);
-
/* fully rounded outline */
glPushMatrix();
glTranslatef(centx, centy, 0.0f);
@@ -2363,7 +2356,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
float col1[4][3]; /* right half, rect bottom to top */
/* draw series of gouraud rects */
- glShadeModel(GL_SMOOTH);
switch (type) {
case UI_GRAD_SV:
@@ -2486,8 +2478,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index b1ca95efe04..b74c4b5f526 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -400,7 +400,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
C, filename,
import_units,
find_chains,
- auto_connect,
+ auto_connect,
fix_orientation,
min_chain_length))
{
@@ -482,7 +482,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
RNA_def_boolean(ot->srna,
"auto_connect", 0, "Auto Connect",
- "set use_connect for parent bones which have exactly one child bone");
+ "Set use_connect for parent bones which have exactly one child bone");
RNA_def_int(ot->srna,
"min_chain_length",
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 9a8382b2136..2b4f94a37ef 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -51,6 +51,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -100,10 +102,10 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
if (!spline->tot_point)
return;
- glColor3ub(0, 0, 0);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
+ glColor3ub(0, 0, 0);
glBegin(GL_LINES);
for (i = 0; i < spline->tot_point; i++) {
@@ -121,7 +123,7 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
glEnd();
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
#endif
@@ -455,7 +457,8 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
case MASK_DT_DASH:
default:
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
#ifdef USE_XOR
glEnable(GL_COLOR_LOGIC_OP);
@@ -463,7 +466,6 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0xaaaa);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, points);
glDrawArrays(draw_method, 0, tot_point);
@@ -473,10 +475,10 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0x5555);
+ GPU_basic_shader_line_stipple(3, 0x5555);
glDrawArrays(draw_method, 0, tot_point);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
break;
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index bcf9ee5c88d..16147bdc7f8 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = masklay_shape->frame;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 01be8f848aa..c4e87614732 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,6 +53,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_draw.h"
#include "GPU_buffers.h"
/* own include */
@@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 242cbf79a83..302ca407add 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -58,26 +58,45 @@
#define MVAL_PIXEL_MARGIN 5.0f
+/* until implement profile = 0 case, need to clamp somewhat above zero */
+#define PROFILE_HARD_MIN 0.15f
+
+#define SEGMENTS_HARD_MAX 1000
+
+/* which value is mouse movement and numeric input controlling? */
+#define OFFSET_VALUE 0
+#define OFFSET_VALUE_PERCENT 1
+#define PROFILE_VALUE 2
+#define SEGMENTS_VALUE 3
+#define NUM_VALUE_KINDS 4
+
+static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset", "profile", "segments"};
+static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f};
+static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX};
+static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f};
+static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f};
+
typedef struct {
BMEditMesh *em;
- float initial_length;
- float pixel_size; /* use when mouse input is interpreted as spatial distance */
+ float initial_length[NUM_VALUE_KINDS];
+ float scale[NUM_VALUE_KINDS];
+ NumInput num_input[NUM_VALUE_KINDS];
+ float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
bool is_modal;
- NumInput num_input;
- float shift_factor; /* The current factor when shift is pressed. Negative when shift not active. */
/* modal only */
float mcenter[2];
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
- "Vertex Only: %s (V), Offset: %s, Segments: %d");
+ "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f");
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
@@ -89,8 +108,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
const char *type_str;
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
- if (hasNumInput(&opdata->num_input)) {
- outputNumInput(&opdata->num_input, offset_str, &sce->unit);
+ if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
+ outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
@@ -101,7 +120,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
- offset_str, RNA_int_get(op->ptr, "segments"));
+ WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
+ offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
ED_area_headerprint(sa, msg);
}
@@ -113,6 +133,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
Scene *scene = CTX_data_scene(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BevelData *opdata;
+ float pixels_per_inch;
+ int i;
if (em->bm->totvertsel == 0) {
return false;
@@ -122,13 +144,25 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
- opdata->shift_factor = -1.0f;
-
- initNumInput(&opdata->num_input);
- opdata->num_input.idx_max = 0;
- opdata->num_input.val_flag[0] |= NUM_NO_NEGATIVE;
- opdata->num_input.unit_sys = scene->unit.system;
- opdata->num_input.unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ opdata->value_mode = OFFSET_VALUE;
+ pixels_per_inch = U.dpi * U.pixelsize;
+
+ for (i = 0; i < NUM_VALUE_KINDS; i++) {
+ opdata->shift_value[i] = -1.0f;
+ /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */
+ opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch;
+
+ initNumInput(&opdata->num_input[i]);
+ opdata->num_input[i].idx_max = 0;
+ opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
+ if (i == SEGMENTS_VALUE) {
+ opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
+ }
+ if (i == OFFSET_VALUE) {
+ opdata->num_input[i].unit_sys = scene->unit.system;
+ }
+ opdata->num_input[i].unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ }
/* avoid the cost of allocating a bm copy */
if (is_modal) {
@@ -136,7 +170,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
opdata->mesh_backup = EDBM_redo_state_store(em);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb,
+ opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
@@ -167,13 +202,15 @@ static bool edbm_bevel_calc(wmOperator *op)
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
}
- if (em->ob)
+ if (em->ob) {
material = CLAMPIS(material, -1, em->ob->totcol - 1);
+ }
EDBM_op_init(em, &bmop, op,
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
"material=%i loop_slide=%b",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide);
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
+ clamp_overlap, material, loop_slide);
BMO_op_exec(em->bm, &bmop);
@@ -185,8 +222,9 @@ static bool edbm_bevel_calc(wmOperator *op)
}
/* no need to de-select existing geometry */
- if (!EDBM_op_finish(em, &bmop, op, true))
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
return false;
+ }
EDBM_mesh_normals_update(opdata->em);
@@ -250,12 +288,37 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed)
+{
+ BevelData *opdata;
+ float mlen[2], len, value, sc, st;
+ int vmode;
+
+ opdata = op->customdata;
+ mlen[0] = opdata->mcenter[0] - event->mval[0];
+ mlen[1] = opdata->mcenter[1] - event->mval[1];
+ len = len_v2(mlen);
+ vmode = opdata->value_mode;
+ if (mode_changed) {
+ /* If current value is not default start value, adjust len so that
+ * the scaling and offset in edbm_bevel_mouse_set_value will
+ * start at current value */
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ sc = opdata->scale[vmode];
+ st = value_start[vmode];
+ if (value != value_start[vmode]) {
+ len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc;
+ }
+ }
+ opdata->initial_length[opdata->value_mode] = len;
+}
+
static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* TODO make modal keymap (see fly mode) */
RegionView3D *rv3d = CTX_wm_region_view3d(C);
BevelData *opdata;
- float mlen[2];
float center_3d[3];
if (!edbm_bevel_init(C, op, true)) {
@@ -270,10 +333,10 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
* ideally this will never happen and should be checked for above */
opdata->mcenter[0] = opdata->mcenter[1] = 0;
}
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
- opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ edbm_bevel_calc_initial_length(op, event, false);
+
+ /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */
+ opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
edbm_bevel_update_header(C, op);
@@ -287,59 +350,72 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
+static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- bool use_dist;
- bool is_percent;
+ int vmode = opdata->value_mode;
float mdiff[2];
- float factor;
+ float value;
mdiff[0] = opdata->mcenter[0] - event->mval[0];
mdiff[1] = opdata->mcenter[1] - event->mval[1];
- is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
- use_dist = !is_percent;
- factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
+ value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]);
+
+ /* Scale according to value mode */
+ value = value_start[vmode] + value * opdata->scale[vmode];
/* Fake shift-transform... */
if (event->shift) {
- if (opdata->shift_factor < 0.0f) {
- opdata->shift_factor = RNA_float_get(op->ptr, "offset");
- if (is_percent) {
- opdata->shift_factor /= 100.0f;
- }
+ if (opdata->shift_value[vmode] < 0.0f) {
+ opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
}
- factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
+ value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode];
}
- else if (opdata->shift_factor >= 0.0f) {
- opdata->shift_factor = -1.0f;
+ else if (opdata->shift_value[vmode] >= 0.0f) {
+ opdata->shift_value[vmode] = -1.0f;
}
- /* clamp differently based on distance/factor */
- if (use_dist) {
- if (factor < 0.0f) factor = 0.0f;
+ /* clamp accordingto value mode, and store value back */
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)(value + 0.5f));
}
else {
- CLAMP(factor, 0.0f, 1.0f);
- if (is_percent) {
- factor *= 100.0f;
- }
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
}
+}
- return factor;
+static void edbm_bevel_numinput_set_value(wmOperator *op)
+{
+ BevelData *opdata = op->customdata;
+ float value;
+ int vmode;
+
+ vmode = opdata->value_mode;
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ applyNumInput(&opdata->num_input[vmode], &value);
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)value);
+ }
+ else {
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
+ }
}
static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- const bool has_numinput = hasNumInput(&opdata->num_input);
+ const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]);
/* Modal numinput active, try to handle numeric inputs first... */
- if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -354,9 +430,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
if (!has_numinput) {
- const float factor = edbm_bevel_mval_factor(op, event);
- RNA_float_set(op->ptr, "offset", factor);
-
+ edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -426,12 +500,18 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (type > BEVEL_AMT_PERCENT) {
type = BEVEL_AMT_OFFSET;
}
+ if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE_PERCENT;
+ else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE;
RNA_property_enum_set(op->ptr, prop, type);
}
- /* Update factor accordingly to new offset_type. */
- if (!has_numinput) {
- RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event));
- }
+ /* Update offset accordingly to new offset_type. */
+ if (!has_numinput &&
+ (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT))
+ {
+ edbm_bevel_mouse_set_value(op, event);
+ }
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -448,6 +528,28 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case PKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == PROFILE_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = PROFILE_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
+ case SKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == SEGMENTS_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = SEGMENTS_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
case VKEY:
if (event->val == KM_RELEASE)
break;
@@ -464,10 +566,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* Modal numinput inactive, try to handle numeric inputs last... */
- if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -518,11 +618,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
- RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
- RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
+ RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
+ RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
+ "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
- "Do not allow beveled edges/vertices to overlap each other");
+ "Do not allow beveled edges/vertices to overlap each other");
RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
- RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
+ RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material",
+ "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 0fd56fbcc4e..a84b8d9dcc8 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2283,7 +2283,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
- /* point to knife edges we've created edges in, edge_array aligned */
+ /* point to knife edges we've created edges in, edge_array aligned */
KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 9e71e646b1a..8868827a11f 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -463,7 +463,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
if ((ulp->l_pair[0] && ulp->l_pair[1]) &&
(ulp->l_pair[0]->e != ulp->l_pair[1]->e))
{
- /* time has come to make a face! */
+ /* time has come to make a face! */
BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
BMFace *f, *f_example = ulp->l_pair[0]->f;
BMLoop *l_iter;
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..9f1602ccfaf 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2910,7 +2910,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 +2982,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);
@@ -3294,7 +3296,9 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
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}));
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index b9d3fd6c8be..b44fbc3ce45 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -49,7 +49,7 @@
# endif
# include "BLI_array_store.h"
-# include "BLI_math_base.h"
+# include "BLI_array_store_utils.h"
/* check on best size later... */
# define ARRAY_CHUNK_SIZE 256
@@ -89,8 +89,7 @@ typedef struct UndoMesh {
#ifdef USE_ARRAY_STORE
/* NULL arrays are considered empty */
- struct {
- /* most data is stored as 'custom' data */
+ struct { /* most data is stored as 'custom' data */
BArrayCustomData *vdata, *edata, *ldata, *pdata;
BArrayState **keyblocks;
BArrayState *mselect;
@@ -105,8 +104,7 @@ typedef struct UndoMesh {
* \{ */
static struct {
- BArrayStore **bs_all;
- int bs_all_len;
+ struct BArrayStore_AtSize bs_stride;
int users;
/* We could have the undo API pass in the previous state, for now store a local list */
@@ -118,57 +116,6 @@ static struct {
} um_arraystore = {NULL};
-static BArrayStore *array_store_at_size_ensure(const int stride)
-{
- if (um_arraystore.bs_all_len < stride) {
- um_arraystore.bs_all_len = stride;
- um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride);
- }
- BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1];
-
- if ((*bs_p) == NULL) {
-#if 0
- unsigned int chunk_count = ARRAY_CHUNK_SIZE;
-#else
- /* calculate best chunk-count to fit a power of two */
- unsigned int chunk_count = ARRAY_CHUNK_SIZE;
- {
- unsigned int size = chunk_count * stride;
- size = power_of_2_max_u(size);
- size = MEM_SIZE_OPTIMAL(size);
- chunk_count = size / stride;
- }
-#endif
-
- (*bs_p) = BLI_array_store_create(stride, chunk_count);
- }
- return *bs_p;
-}
-
-static BArrayStore *array_store_at_size_get(const int stride)
-{
- BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len);
- return um_arraystore.bs_all[stride - 1];
-}
-
-#ifdef DEBUG_PRINT
-static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted)
-{
- size_t size_compacted = 0;
- size_t size_expanded = 0;
- for (int i = 0; i < um_arraystore.bs_all_len; i++) {
- BArrayStore *bs = um_arraystore.bs_all[i];
- if (bs) {
- size_compacted += BLI_array_store_calc_size_compacted_get(bs);
- size_expanded += BLI_array_store_calc_size_expanded_get(bs);
- }
- }
-
- *r_size_expanded = size_expanded;
- *r_size_compacted = size_compacted;
-}
-#endif
-
static void um_arraystore_cd_compact(
struct CustomData *cdata, const size_t data_len,
bool create,
@@ -194,7 +141,7 @@ static void um_arraystore_cd_compact(
}
const int stride = CustomData_sizeof(type);
- BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
const int layer_len = layer_end - layer_start;
if (create) {
@@ -299,7 +246,7 @@ static void um_arraystore_cd_free(BArrayCustomData *bcd)
while (bcd) {
BArrayCustomData *bcd_next = bcd->next;
const int stride = CustomData_sizeof(bcd->type);
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
for (int i = 0; i < bcd->states_len; i++) {
if (bcd->states[i]) {
BLI_array_store_state_remove(bs, bcd->states[i]);
@@ -328,7 +275,7 @@ static void um_arraystore_compact_ex(
if (me->key && me->key->totkey) {
const size_t stride = me->key->elemsize;
- BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
if (create) {
um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__);
}
@@ -355,7 +302,7 @@ static void um_arraystore_compact_ex(
if (create) {
BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL;
const size_t stride = sizeof(*me->mselect);
- BArrayStore *bs = array_store_at_size_ensure(stride);
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE);
um->store.mselect = BLI_array_store_state_add(
bs, me->mselect, (size_t)me->totselect * stride, state_reference);
}
@@ -384,7 +331,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref
{
#ifdef DEBUG_PRINT
size_t size_expanded_prev, size_compacted_prev;
- um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev);
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
#endif
#ifdef DEBUG_TIME
@@ -400,7 +347,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref
#ifdef DEBUG_PRINT
{
size_t size_expanded, size_compacted;
- um_arraystore_memory_usage(&size_expanded, &size_compacted);
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted);
const double percent_total = size_expanded ?
(((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
@@ -483,7 +430,7 @@ static void um_arraystore_free(UndoMesh *um)
if (um->store.keyblocks) {
const size_t stride = me->key->elemsize;
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
for (int i = 0; i < me->key->totkey; i++) {
BArrayState *state = um->store.keyblocks[i];
BLI_array_store_state_remove(bs, state);
@@ -494,7 +441,7 @@ static void um_arraystore_free(UndoMesh *um)
if (um->store.mselect) {
const size_t stride = sizeof(*me->mselect);
- BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
BArrayState *state = um->store.mselect;
BLI_array_store_state_remove(bs, state);
um->store.mselect = NULL;
@@ -508,15 +455,7 @@ static void um_arraystore_free(UndoMesh *um)
#ifdef DEBUG_PRINT
printf("mesh undo store: freeing all data!\n");
#endif
- for (int i = 0; i < um_arraystore.bs_all_len; i += 1) {
- if (um_arraystore.bs_all[i]) {
- BLI_array_store_destroy(um_arraystore.bs_all[i]);
- }
- }
-
- MEM_freeN(um_arraystore.bs_all);
- um_arraystore.bs_all = NULL;
- um_arraystore.bs_all_len = 0;
+ BLI_array_store_at_size_clear(&um_arraystore.bs_stride);
#ifdef USE_ARRAY_STORE_THREAD
BLI_task_pool_free(um_arraystore.task_pool);
@@ -624,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){
@@ -698,7 +639,7 @@ static void free_undo(void *um_v)
MEM_freeN(me->key);
}
- BKE_mesh_free(me, false);
+ BKE_mesh_free(me);
MEM_freeN(me);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 99be37845ee..5101608246a 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);
+ }
+ }
}
/**
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 880417a00cf..08ed9813456 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"
@@ -1112,12 +1113,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);
- if (scene->basact == base) scene->basact = NULL;
MEM_freeN(base);
+ DAG_id_type_tag(bmain, ID_OB);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1134,6 +1141,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;
@@ -1149,6 +1169,12 @@ static int object_delete_exec(bContext *C, wmOperator *op)
if (scene_iter != scene && !(scene_iter->id.lib)) {
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);
}
}
@@ -1292,7 +1318,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_animdata_free(&ob->id);
+ BKE_animdata_free(&ob->id, true);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1384,7 +1410,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
}
}
- /* The same how BKE_object_unlink detects which object proxies to clear. */
if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) {
for (object = bmain->object.first; object; object = object->id.next) {
if (object->proxy_group == base->object) {
@@ -1605,7 +1630,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(scene, newob);
+ ED_rigidbody_object_remove(bmain, scene, newob);
}
}
else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index efd1ebbd51b..d7b7fd7040e 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
/************************ add constraint operators *********************/
/* get the Object and/or PoseChannel to use as target */
-static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
+static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
- short only_curve = 0, only_mesh = 0, only_ob = 0;
- short found = 0;
+ bool only_curve = false, only_mesh = false, only_ob = false;
+ bool found = false;
/* clear tar_ob and tar_pchan fields before use
* - assume for now that both always exist...
@@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_ROTLIMIT:
case CONSTRAINT_TYPE_SIZELIMIT:
case CONSTRAINT_TYPE_SAMEVOL:
- return 0;
+ return false;
/* restricted target-type constraints -------------- */
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
@@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_CLAMPTO:
case CONSTRAINT_TYPE_FOLLOWPATH:
case CONSTRAINT_TYPE_SPLINEIK:
- only_curve = 1;
- only_ob = 1;
- add = 0;
+ only_curve = true;
+ only_ob = true;
+ add = false;
break;
/* mesh only? */
case CONSTRAINT_TYPE_SHRINKWRAP:
- only_mesh = 1;
- only_ob = 1;
- add = 0;
+ only_mesh = true;
+ only_ob = true;
+ add = false;
break;
/* object only - add here is ok? */
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = 1;
+ only_ob = true;
break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
- if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
+ if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
@@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
if (pchan != pchanact) {
*tar_ob = obact;
*tar_pchan = pchan;
- found = 1;
+ found = true;
break;
}
@@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
}
/* if not yet found, try selected Objects... */
- if (found == 0) {
+ if (found == false) {
/* search in selected objects context */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* just use the first object we encounter (that isn't the active object)
* and which fulfills the criteria for the object-target that we've got
*/
- if ((ob != obact) &&
- ((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
- {
- /* set target */
- *tar_ob = ob;
- found = 1;
-
- /* perform some special operations on the target */
- if (only_curve) {
- /* Curve-Path option must be enabled for follow-path constraints to be able to work */
- Curve *cu = (Curve *)ob->data;
- cu->flag |= CU_PATH;
+ if (ob != obact) {
+ /* for armatures in pose mode, look inside the armature for the active bone
+ * so that we set up cross-armature constraints with less effort
+ */
+ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
+ (!only_curve && !only_mesh))
+ {
+ /* just use the active bone, and assume that it is visible + usable */
+ *tar_ob = ob;
+ *tar_pchan = BKE_pose_channel_active(ob);
+ found = true;
+
+ break;
+ }
+ else if (((!only_curve) || (ob->type == OB_CURVE)) &&
+ ((!only_mesh) || (ob->type == OB_MESH)))
+ {
+ /* set target */
+ *tar_ob = ob;
+ found = true;
+
+ /* perform some special operations on the target */
+ if (only_curve) {
+ /* Curve-Path option must be enabled for follow-path constraints to be able to work */
+ Curve *cu = (Curve *)ob->data;
+ cu->flag |= CU_PATH;
+ }
+
+ break;
}
-
- break;
}
}
CTX_DATA_END;
}
/* if still not found, add a new empty to act as a target (if allowed) */
- if ((found == 0) && (add)) {
+ if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Base *base = BASACT, *newbase = NULL;
@@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
/* make our new target the new object */
*tar_ob = obt;
- found = 1;
+ found = true;
}
/* return whether there's any target */
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 06200778ee5..01a567931b3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -946,6 +946,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
cu1 = base->object->data;
cu1->spacemode = cu->spacemode;
+ cu1->align_y = cu->align_y;
cu1->spacing = cu->spacing;
cu1->linedist = cu->linedist;
cu1->shear = cu->shear;
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 76a8a68c42d..bcdd170c53c 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -43,6 +43,7 @@
#include "BKE_depsgraph.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_group_unlink(bmain, group);
+ 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_relations.c b/source/blender/editors/object/object_relations.c
index 2f10f83e276..94d1a258063 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -437,7 +437,7 @@ typedef enum eObClearParentTypes {
EnumPropertyItem prop_clear_parent_types[] = {
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
- "Completely clear the parenting relationship, including involved modifiers is any"},
+ "Completely clear the parenting relationship, including involved modifiers if any"},
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
"As 'Clear Parent', but keep the current visual transformations of the object"},
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 3da3a451d66..30c102b70c5 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1173,7 +1173,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag)
}
}
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
@@ -1289,7 +1289,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
PE_hide_keys_time(scene, edit, CFRA);
/* regenerate path caches */
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1634,7 +1634,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
int p;
int k;
- const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
RNG *rng;
@@ -2288,7 +2288,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
if (ELEM(NULL, new_pars, new_points)) {
- /* allocation error! */
+ /* allocation error! */
if (new_pars)
MEM_freeN(new_pars);
if (new_points)
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index f95599592b2..1bfc162a331 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -41,6 +41,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -70,7 +71,7 @@ static int ED_operator_rigidbody_con_active_poll(bContext *C)
}
-bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -81,7 +82,7 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints");
+ rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
@@ -90,11 +91,12 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
/* add constraint to rigid body constraint group */
BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
+void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -102,6 +104,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -112,6 +115,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
Object *ob = (scene) ? OBACT : NULL;
@@ -124,7 +128,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* apply to active object */
- changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -160,6 +164,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = (scene) ? OBACT : NULL;
@@ -173,7 +178,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- ED_rigidbody_constraint_remove(scene, ob);
+ ED_rigidbody_constraint_remove(bmain, scene, ob);
}
/* send updates */
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 26d8af82b2d..30597d95497 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -46,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -87,7 +88,7 @@ static int ED_operator_rigidbody_add_poll(bContext *C)
/* ----------------- */
-bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -107,7 +108,7 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(G.main, "RigidBodyWorld");
+ rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
}
/* make rigidbody object settings */
@@ -120,12 +121,13 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
/* add object to rigid body group */
BKE_group_object_add(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_object_remove(Scene *scene, Object *ob)
+void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -133,6 +135,7 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -143,13 +146,14 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
/* apply to active object */
- changed = ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -186,13 +190,14 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot)
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bool changed = false;
/* apply to active object */
if (!ELEM(NULL, ob, ob->rigidbody_object)) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
@@ -232,13 +237,14 @@ void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed = false;
/* create rigid body objects and add them to the world's group */
CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
- changed |= ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
}
CTX_DATA_END;
@@ -277,6 +283,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bool changed = false;
@@ -284,7 +291,7 @@ static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
{
if (ob->rigidbody_object) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index f4260a0cd33..132c3fa5438 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -70,6 +70,7 @@
#include "BKE_icons.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
@@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied material */
BLI_remlink(&pr_main->mat, sp->matcopy);
- BKE_material_free_ex(sp->matcopy, false);
+ BKE_material_free(sp->matcopy);
properties = IDP_GetProperties((ID *)sp->matcopy, false);
if (properties) {
@@ -862,7 +863,9 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
- BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */
+ /* T32865 - we need to unlink the texture copies, unlike for materials */
+ BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true);
+ BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
if (properties) {
@@ -878,6 +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_lamp_free(sp->lampcopy);
properties = IDP_GetProperties((ID *)sp->lampcopy, false);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index cbf87062955..93bac3f6660 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -327,6 +327,13 @@ float glaGetOneFloat(int param)
return v;
}
+int glaGetOneInt(int param)
+{
+ GLint v;
+ glGetIntegerv(param, &v);
+ return v;
+}
+
void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
{
GLubyte dummy = 0;
@@ -579,6 +586,10 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
+
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
/* Don't use safe RasterPos (slower) if we can avoid it. */
if (rast_x >= 0 && rast_y >= 0) {
glRasterPos2f(rast_x, rast_y);
@@ -610,6 +621,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index a459f982ada..62aeca4b9d1 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -45,6 +45,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene)
ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
- BKE_scene_unlink(bmain, scene, newscene);
+ BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_libblock_free(bmain, scene);
return true;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f340f716ccb..0c0a6c93b3e 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2479,7 +2479,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Toggle Fullscreen Area";
+ ot->name = "Toggle Maximize Area";
ot->description = "Toggle display selected area as fullscreen/maximized";
ot->idname = "SCREEN_OT_screen_full_area";
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index a716cae56dd..941f19ca0f0 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -401,7 +401,7 @@ static void image_undo_end(void)
UndoImageTile *tmp_tile = tile->next;
deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
MEM_freeN(tile->rect.pt);
- BLI_freelinkN (lb, tile);
+ BLI_freelinkN(lb, tile);
tile = tmp_tile;
}
else {
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d273f8320a1..6ed969cb270 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -202,7 +202,7 @@ typedef struct ProjPaintImage {
*/
typedef struct ProjStrokeHandle {
/* Support for painting from multiple views at once,
- * currently used to impliment summetry painting,
+ * currently used to impliment symmetry painting,
* we can assume at least the first is set while painting. */
struct ProjPaintState *ps_views[8];
int ps_views_tot;
@@ -717,7 +717,7 @@ static bool project_paint_PickColor(
}
/**
- * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
+ * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusion test)
* \return
* - `0`: no occlusion
* - `-1`: no occlusion but 2D intersection is true
@@ -3717,7 +3717,7 @@ static void project_paint_prepare_all_faces(
}
/* tfbase here should be non-null! */
- BLI_assert (mloopuv_base != NULL);
+ BLI_assert(mloopuv_base != NULL);
if (is_face_sel && tpage) {
ProjPaintFaceCoSS coSS;
@@ -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_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b6a7d671882..7e05ab929ae 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -101,6 +101,10 @@ bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight);
bool ED_vpaint_smooth(struct Object *ob);
+typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
+
+bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data);
+
void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_weight_paint(struct wmOperatorType *ot);
void PAINT_OT_weight_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index da7667c775e..bf923415f01 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -315,6 +315,241 @@ static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \name Vertex Color Transformations
+ * \{ */
+
+struct VPaintTx_BrightContrastData {
+ /* pre-calculated */
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_BrightContrastData *data = user_data;
+
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * col[i] + data->offset;
+ }
+}
+
+static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ gain = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (brightness + delta);
+ }
+ }
+
+ const struct VPaintTx_BrightContrastData user_data = {
+ .gain = gain,
+ .offset = offset,
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Bright/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+struct VPaintTx_HueSatData {
+ float hue;
+ float sat;
+ float val;
+};
+
+static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_HueSatData *data = user_data;
+ float hsv[3];
+ rgb_to_hsv_v(col, hsv);
+
+ hsv[0] += (data->hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= data->sat;
+ hsv[2] *= data->val;
+
+ hsv_to_rgb_v(hsv, r_col);
+}
+
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_HueSatData user_data = {
+ .hue = RNA_float_get(op->ptr, "h"),
+ .sat = RNA_float_get(op->ptr, "s"),
+ .val = RNA_float_get(op->ptr, "v"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
+{
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = 1.0f - col[i];
+ }
+}
+
+static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+struct VPaintTx_LevelsData {
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_LevelsData *data = user_data;
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * (col[i] + data->offset);
+ }
+}
+
+static int vertex_color_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_LevelsData user_data = {
+ .gain = RNA_float_get(op->ptr, "gain"),
+ .offset = RNA_float_get(op->ptr, "offset"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+/** \} */
+
+
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -1112,6 +1347,11 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_color_set);
WM_operatortype_append(PAINT_OT_vertex_color_smooth);
+ WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast);
+ WM_operatortype_append(PAINT_OT_vertex_color_hsv);
+ WM_operatortype_append(PAINT_OT_vertex_color_invert);
+ WM_operatortype_append(PAINT_OT_vertex_color_levels);
+
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 65857cccb15..aa17cb02fe5 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -160,11 +162,11 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ GPU_basic_shader_line_width(3.0);
glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
- glLineWidth(3.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -175,7 +177,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
}
glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
- glLineWidth(1.0);
+ GPU_basic_shader_line_width(1.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -185,7 +187,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
x, y);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -1156,7 +1158,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE) {
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- paint_stroke_line_end (C, op, stroke, mouse);
+ paint_stroke_line_end(C, op, stroke, mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 15ab4ca04a7..87855879ec5 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -502,6 +502,51 @@ bool ED_vpaint_smooth(Object *ob)
return true;
}
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
+bool ED_vpaint_color_transform(
+ struct Object *ob,
+ VPaintTransform_Callback vpaint_tx_fn,
+ const void *user_data)
+{
+ Mesh *me;
+ const MPoly *mp;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL) ||
+ (me->mloopcol == NULL && (make_vertexcol(ob) == false)))
+ {
+ return false;
+ }
+
+ const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ mp = me->mpoly;
+
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+
+ if (do_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ for (int j = 0; j < mp->totloop; j++, lcol++) {
+ float col[3];
+ rgb_uchar_to_float(col, &lcol->r);
+
+ vpaint_tx_fn(col, user_data, col);
+
+ rgb_float_to_uchar(&lcol->r, col);
+ }
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */
#if 0
void vpaint_dogamma(Scene *scene)
@@ -1323,7 +1368,7 @@ static bool do_weight_paint_normalize_all_locked(
/**
* \note same as function above except it does a second pass without active group
- * if nomalize fails with it.
+ * if normalize fails with it.
*/
static void do_weight_paint_normalize_all_locked_try_active(
MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
@@ -1340,7 +1385,7 @@ static void do_weight_paint_normalize_all_locked_try_active(
* - With 1.0 weight painted into active:
* nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
* - With 0.0 weight painted into active:
- * no unlocked groups; first pass did nothing; increaze 0 to fit.
+ * no unlocked groups; first pass did nothing; increase 0 to fit.
*/
do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c173156de3a..0931456058d 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,49 @@ 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) {
+ sculpt_dynamic_topology_enable(C);
+ }
+ 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/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index a4d9a920cbb..4931426d62e 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 50e10e7e154..408eb38d386 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_lasso(struct wmOperatorType *ot);
+void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
void ACTION_OT_select_linked(struct wmOperatorType *ot);
void ACTION_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index f69f9944f8a..a261202b690 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -59,6 +59,8 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_clickselect);
WM_operatortype_append(ACTION_OT_select_all_toggle);
WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_lasso);
+ WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
WM_operatortype_append(ACTION_OT_select_linked);
WM_operatortype_append(ACTION_OT_select_more);
@@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
+ /* region select */
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index f2813b2a8d3..7900217e28e 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
+/* ******************** Region Select Operators ***************************** */
+/* "Region Select" operators include the Lasso and Circle Select operators.
+ * These two ended up being lumped together, as it was easier in the
+ * original Graph Editor implementation of these to do it this way.
+ */
+
+static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ KeyframeEditData ked;
+ KeyframeEditFunc ok_cb, select_cb;
+ View2D *v2d = &ac->ar->v2d;
+ rctf rectf, scaled_rectf;
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+
+ /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
+ UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get beztriple editing/validation funcs */
+ select_cb = ANIM_editkeyframes_select(selectmode);
+ ok_cb = ANIM_editkeyframes_ok(mode);
+
+ /* init editing data */
+ memset(&ked, 0, sizeof(KeyframeEditData));
+ if (mode == BEZT_OK_CHANNEL_LASSO) {
+ KeyframeEdit_LassoData *data_lasso = data;
+ data_lasso->rectf_scaled = &scaled_rectf;
+ ked.data = data_lasso;
+ }
+ else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
+ KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
+ else {
+ ked.data = &scaled_rectf;
+ }
+
+ /* loop over data, doing region select */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* get new vertical minimum extent of channel */
+ ymin = ymax - ACHANNEL_STEP;
+
+ /* compute midpoint of channel (used for testing if the key is in the region or not) */
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
+
+ /* if channel is mapped in NLA, apply correction
+ * - Apply to the bounds being checked, not all the keyframe points,
+ * to avoid having scaling everything
+ * - Save result to the scaled_rect, which is all that these operators
+ * will read from
+ */
+ if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
+ ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
+ ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
+ ked.f1 = rectf.xmin;
+ ked.f2 = rectf.xmax;
+ }
+
+ /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
+ * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
+ * with the properly remapped ked.f1/f2 values, when needed
+ */
+ scaled_rectf.xmin = ked.f1;
+ scaled_rectf.xmax = ked.f2;
+ scaled_rectf.ymin = ymin;
+ scaled_rectf.ymax = ymax;
+
+ /* perform vertical suitability check (if applicable) */
+ if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
+ !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ {
+ /* loop over data selecting */
+ switch (ale->type) {
+ case ANIMTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd = ale->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_GPLAYER:
+ {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ case ANIMTYPE_MASKDATABLOCK:
+ {
+ Mask *mask = ale->data;
+ MaskLayer *masklay;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_MASKLAYER:
+ {
+ ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ default:
+ ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
+ break;
+ }
+ }
+
+ /* set minimum extent to be the maximum of the next channel */
+ ymax = ymin;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ----------------------------------- */
+
+static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso;
+ rcti rect;
+ rctf rect_fl;
+
+ short selectmode;
+ bool extend;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data_lasso.rectf_view = &rect_fl;
+ data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
+ if (data_lasso.mcords == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* clear all selection if not extending selection */
+ extend = RNA_boolean_get(op->ptr, "extend");
+ if (!extend)
+ deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
+
+ if (!RNA_boolean_get(op->ptr, "deselect"))
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ /* get settings from operator */
+ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_rctf_rcti_copy(&rect_fl, &rect);
+
+ /* apply borderselect action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
+
+ MEM_freeN((void *)data_lasso.mcords);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_lasso(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lasso Select";
+ ot->description = "Select keyframe points using lasso selection";
+ ot->idname = "ACTION_OT_select_lasso";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = actkeys_lassoselect_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ------------------- */
+
+static int action_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+
+ KeyframeEdit_CircleData data = {0};
+ rctf rect_fl;
+
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ /* apply region select action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "ACTION_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = action_circle_select_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 60240109432..671d6bb083e 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_action_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa)
// XXX re-sizing y-extents of tot should go here?
}
+static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceAction *sact = (SpaceAction *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)sact->ads.filter_grp == old_id) {
+ sact->ads.filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
@@ -631,7 +645,8 @@ void ED_spacetype_action(void)
st->keymap = action_keymap;
st->listener = action_listener;
st->refresh = action_refresh;
-
+ st->id_remap = action_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 42e2d6b90f0..5b03bdd7761 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
-
-void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
-{
- if (sbuts->pinid == id) {
- sbuts->pinid = NULL;
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
-
- if (sbuts->path) {
- ButsContextPath *path = sbuts->path;
- int i;
-
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].id.data == id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
- }
-}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 126a27c36cb..e4c23ad74f8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -45,6 +45,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "RNA_access.h"
+
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
ED_area_tag_redraw(sa);
}
+static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceButs *sbuts = (SpaceButs *)slink;
+
+ if (sbuts->pinid == old_id) {
+ sbuts->pinid = new_id;
+ if (new_id == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == old_id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (new_id == NULL) {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+ else {
+ RNA_id_pointer_create(new_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+
+ if (sbuts->texuser) {
+ ButsContextTexture *ct = sbuts->texuser;
+ if ((ID *)ct->texture == old_id) {
+ ct->texture = (Tex *)new_id;
+ }
+ BLI_freelistN(&ct->users);
+ ct->user = NULL;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
@@ -406,7 +461,8 @@ void ED_spacetype_buttons(void)
st->keymap = buttons_keymap;
st->listener = buttons_area_listener;
st->context = buttons_context;
-
+ st->id_remap = buttons_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 1c5be3d1fb5..695d04d3850 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -336,8 +336,10 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
/* draw boundary border for frame if stabilization is enabled */
if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -357,7 +359,7 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
glPopMatrix();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -627,8 +629,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -638,7 +640,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -647,8 +649,11 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glTranslate2fv(marker_pos);
if (tiny) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
@@ -713,8 +718,12 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
}
- if (tiny)
- glDisable(GL_LINE_STIPPLE);
+ if (tiny) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
glPopMatrix();
}
@@ -852,16 +861,12 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
glLineWidth(outline ? 3.0f : 1.0f);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xaaaa);
-
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2fv(tilt_ctrl);
glEnd();
- glDisable(GL_LINE_STIPPLE);
-
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
/* slider to control pattern tilt */
draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px);
@@ -1133,11 +1138,14 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
const bool thick = draw_outline && !tiny;
if (stipple) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
- glLineWidth(thick ? 3.0f : 1.0f);
+ GPU_basic_shader_line_width(thick ? 3.0f : 1.0f);
/* Draw rectangle itself. */
glBegin(GL_LINE_LOOP);
@@ -1169,8 +1177,12 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
glPopAttrib();
}
- if (stipple)
- glDisable(GL_LINE_STIPPLE);
+ if (stipple) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
}
/* Draw sliders. */
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e1d4e4fabc5..415839ab761 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -1512,6 +1513,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/********************* registration ********************/
+static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceClip *sclip = (SpaceClip *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)sclip->clip == old_id) {
+ sclip->clip = (MovieClip *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)sclip->mask_info.mask == old_id) {
+ sclip->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
@@ -1531,6 +1551,7 @@ void ED_spacetype_clip(void)
st->context = clip_context;
st->dropboxes = clip_dropboxes;
st->refresh = clip_refresh;
+ st->id_remap = clip_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 71e38f72a7a..a55b18a2212 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d83a7d5ea62..c42ff120102 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
BLI_add_slash(params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
retval = FILE_SELECT_DIR;
}
}
@@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_add_slash(sfile->params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
@@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- /* if not browsing in .blend file, we still want to check whether the path is a directory */
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
- ED_file_change_dir(C, false);
- }
- else {
- ED_file_change_dir(C, true);
- }
- }
- else {
- ED_file_change_dir(C, true);
- }
+ ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
@@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (BLI_is_file(sfile->params->dir)) {
- char path[sizeof(sfile->params->dir)];
- BLI_strncpy(path, sfile->params->dir, sizeof(path));
- BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ if (!file_is_dir(sfile, sfile->params->dir)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *group, *name;
+
+ if (BLI_is_file(sfile->params->dir)) {
+ char path[sizeof(sfile->params->dir)];
+ BLI_strncpy(path, sfile->params->dir, sizeof(path));
+ BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
+ if (group) {
+ BLI_path_append(tdir, sizeof(tdir), group);
+ }
+ BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
+ if (name) {
+ BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
+ }
+ else {
+ sfile->params->file[0] = '\0';
+ }
+ }
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (BLI_exists(sfile->params->dir)) {
+ if (file_is_dir(sfile, sfile->params->dir)) {
/* if directory exists, enter it immediately */
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
#endif
else {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
+ char tdir[FILE_MAX_LIBEXTRA];
- /* if not, ask to create it and enter if confirmed */
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "directory", sfile->params->dir);
- RNA_boolean_set(&ptr, "open", true);
-
- if (lastdir)
+ /* If we are 'inside' a blend library, we cannot do anything... */
+ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
-
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ }
+ else {
+ /* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "directory", sfile->params->dir);
+ RNA_boolean_set(&ptr, "open", true);
+
+ if (lastdir)
+ BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ }
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_filename_make_safe(sfile->params->file);
if (matches) {
- /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
- sfile->params->file[0] = '\0';
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
@@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
-
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (BLI_is_dir(filepath)) {
+ if (file_is_dir(sfile, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
- else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- BLI_add_slash(filepath);
- if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
- BLI_cleanup_dir(G.main->name, filepath);
- BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
- ED_file_change_dir(C, false);
- UI_textbutton_activate_but(C, but);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- }
- }
}
else if (matches > 1) {
file_draw_check(C);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 3c007f25da3..f19e301064d 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -25,6 +25,9 @@
*/
#include "BLI_rect.h"
+#include "BLI_fileops.h"
+
+#include "BLO_readfile.h"
#include "BKE_context.h"
@@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
+
+/* Cannot directly use BLI_is_dir in libloading context... */
+bool file_is_dir(struct SpaceFile *sfile, const char *path)
+{
+ if (sfile->params->type == FILE_LOADLIB) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
+ /* .blend file itself and group are considered as directories, not final datablock names. */
+ return name ? false : true;
+ }
+ }
+ return BLI_is_dir(path);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 8e1f781827a..5e9eb1f9207 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
@@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist)
if (filelist->max_recursion) {
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
* root path is a blend file. */
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!filelist_islibrary(filelist, dir, NULL)) {
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
}
@@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
{
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
@@ -1925,7 +1925,8 @@ static bool file_is_blend_backup(const char *str)
return (retval);
}
-static int path_extension_type(const char *path)
+/* TODO: Maybe we should move this to BLI? On the other hand, it's using defines from spacefile area, so not sure... */
+int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
return FILE_TYPE_BLENDER;
@@ -1977,12 +1978,12 @@ static int file_extension_type(const char *dir, const char *relpath)
{
char path[FILE_MAX];
BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return path_extension_type(path);
+ return ED_path_extension_type(path);
}
int ED_file_extension_icon(const char *path)
{
- int type = path_extension_type(path);
+ const int type = ED_path_extension_type(path);
switch (type) {
case FILE_TYPE_BLENDER:
@@ -2112,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
return 0;
}
+/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
@@ -2207,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
FileListInternEntry *entry;
LinkNode *ln, *names;
int i, nnames, idcode = 0, nbr_entries = 0;
- char dir[FILE_MAX], *group;
+ char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
struct BlendHandle *libfiledata = NULL;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index bf90a4ea170..175d83506c6 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void ED_file_change_dir(bContext *C, const bool checkdir)
+void ED_file_change_dir(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (checkdir && !BLI_is_dir(sfile->params->dir)) {
+ if (!file_is_dir(sfile, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 6b860990c10..478dbd3d9c0 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", false);
-
+
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "axis_range", false);
RNA_boolean_set(kmi->ptr, "include_handles", true);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", true);
-
+
+ /* region select */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
-
+
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* column select */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index eb786d872ec..67b960bfa53 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
+ *
+ * The selection backend is also reused for the Lasso and Circle select operators.
*/
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
@@ -245,12 +247,12 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
if (mode == BEZT_OK_REGION_LASSO) {
- struct KeyframeEdit_LassoData *data_lasso = data;
+ KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
else if (mode == BEZT_OK_REGION_CIRCLE) {
- struct KeyframeEdit_CircleData *data_circle = data;
+ KeyframeEdit_CircleData *data_circle = data;
data_circle->rectf_scaled = &scaled_rectf;
ked.data = data;
}
@@ -265,27 +267,27 @@ static void borderselect_graphkeys(
}
else
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
-
+
mapping_flag |= ANIM_get_normalization_flags(ac);
-
+
/* loop over data, doing border select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
*/
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
-
+
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
-
+
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
* (which uses ked.data, i.e. rectf)
@@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
}
+
+/* ------------------- */
+
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso = {0};
rcti rect;
rctf rect_fl;
+
short selectmode;
bool incl_handles;
bool extend;
-
- struct KeyframeEdit_LassoData data_lasso;
-
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data_lasso.rectf_view = &rect_fl;
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
if (data_lasso.mcords == NULL)
return OPERATOR_CANCELLED;
-
+
/* clear all selection if not extending selection */
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
-
+
if (!RNA_boolean_get(op->ptr, "deselect"))
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
-
- if (ac.spacetype == SPACE_IPO) {
+
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
-
+
/* get settings from operator */
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
-
BLI_rctf_rcti_copy(&rect_fl, &rect);
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
-
+
MEM_freeN((void *)data_lasso.mcords);
-
-
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+
return OPERATOR_FINISHED;
}
-
void GRAPH_OT_select_lasso(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lasso Select";
ot->description = "Select keyframe points using lasso selection";
ot->idname = "GRAPH_OT_select_lasso";
-
+
/* api callbacks */
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = graphkeys_lassoselect_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_lasso_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+/* ------------------- */
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
- short selectmode;
- bool incl_handles;
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+ bool incl_handles = false;
+
+ KeyframeEdit_CircleData data = {0};
rctf rect_fl;
- struct KeyframeEdit_CircleData data;
+
float x = RNA_int_get(op->ptr, "x");
float y = RNA_int_get(op->ptr, "y");
float radius = RNA_int_get(op->ptr, "radius");
@@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data.mval[0] = x;
data.mval[1] = y;
data.radius_squared = radius * radius;
data.rectf_view = &rect_fl;
- if (gesture_mode == GESTURE_MODAL_SELECT)
- selectmode = SELECT_ADD;
- else
- selectmode = SELECT_SUBTRACT;
-
rect_fl.xmin = x - radius;
rect_fl.xmax = x + radius;
rect_fl.ymin = y - radius;
rect_fl.ymax = y + radius;
- if (ac.spacetype == SPACE_IPO) {
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index c6a8a9753d1..8ae5932f3fd 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -610,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
break;
}
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
case FCURVE_COLOR_AUTO_RAINBOW:
default:
{
@@ -627,6 +673,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
}
+static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceIpo *sgraph = (SpaceIpo *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)sgraph->ads->filter_grp == old_id) {
+ sgraph->ads->filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
@@ -644,7 +703,8 @@ void ED_spacetype_ipo(void)
st->keymap = graphedit_keymap;
st->listener = graph_listener;
st->refresh = graph_refresh;
-
+ st->id_remap = graph_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 8db5a8f9bd3..06caf930988 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -2979,7 +2979,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf->zbuf) {
info->z = ibuf->zbuf[y * ibuf->x + x];
info->zp = &info->z;
- if (ibuf->zbuf == (int*)ibuf->rect) {
+ if (ibuf->zbuf == (int *)ibuf->rect) {
info->colp = NULL;
}
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 168f9c0dfdf..35a658eac23 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -28,6 +28,7 @@
* \ingroup spimage
*/
+#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_mask_types.h"
#include "DNA_meshdata_types.h"
@@ -44,6 +45,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -981,6 +983,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
+static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceImage *simg = (SpaceImage *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)simg->image == old_id) {
+ simg->image = (Image *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)simg->gpd == old_id) {
+ simg->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+
+ if ((ID *)simg->mask_info.mask == old_id) {
+ simg->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/**************************** spacetype *****************************/
/* only called once, from space/spacetypes.c */
@@ -1002,7 +1029,8 @@ void ED_spacetype_image(void)
st->refresh = image_refresh;
st->listener = image_listener;
st->context = image_context;
-
+ st->id_remap = image_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 243a522011b..69966e9bf34 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -38,7 +38,10 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "DNA_gpencil_types.h"
+
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "ED_space_api.h"
@@ -300,6 +303,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar)
/**************************** spacetype *****************************/
+static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceLogic *slog = (SpaceLogic *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)slog->gpd == old_id) {
+ slog->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_logic(void)
{
@@ -317,7 +335,8 @@ void ED_spacetype_logic(void)
st->keymap = logic_keymap;
st->refresh = logic_refresh;
st->context = logic_context;
-
+ st->id_remap = logic_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index e2b36c5b5ae..3b5604087b9 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
+static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNla *snla = (SpaceNla *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)snla->ads->filter_grp == old_id) {
+ snla->ads->filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
@@ -517,7 +531,8 @@ void ED_spacetype_nla(void)
st->operatortypes = nla_operatortypes;
st->listener = nla_listener;
st->keymap = nla_keymap;
-
+ st->id_remap = nla_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 6ae72e2a164..ffe510016ff 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -740,34 +740,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
-void ED_node_id_unref(SpaceNode *snode, const ID *id)
-{
- if (GS(id->name) == ID_SCE) {
- if (snode->id == id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
- }
- else if (GS(id->name) == ID_OB) {
- if (snode->from == id) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
- }
-}
-
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index df484724fc5..4ef703c8994 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -28,6 +28,7 @@
* \ingroup spnode
*/
+#include "DNA_gpencil_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul
return 0;
}
+static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNode *snode = (SpaceNode *)slink;
+
+ if (GS(old_id->name) == ID_SCE) {
+ if (snode->id == old_id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ BLI_freelistN(&snode->treepath);
+
+ /* XXX Untested in case new_id != NULL... */
+ snode->id = new_id;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(old_id->name) == ID_OB) {
+ if (snode->from == old_id) {
+ if (new_id == NULL) {
+ snode->flag &= ~SNODE_PIN;
+ }
+ snode->from = new_id;
+ }
+ }
+ else if (GS(old_id->name) == ID_GD) {
+ if ((ID *)snode->gpd == old_id) {
+ snode->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_node(void)
{
@@ -840,6 +876,7 @@ void ED_spacetype_node(void)
st->refresh = node_area_refresh;
st->context = node_context;
st->dropboxes = node_dropboxes;
+ st->id_remap = node_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index b624c7cba75..43e9c262172 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -502,6 +502,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
"Library path '%s' does not exist, correct this before saving", expanded);
}
+ else if (lib->id.tag & LIB_TAG_MISSING) {
+ BKE_reportf(CTX_wm_reports(C), RPT_INFO,
+ "Library path '%s' is now valid, please reload the library", expanded);
+ lib->id.tag &= ~LIB_TAG_MISSING;
+ }
}
}
else {
@@ -1579,11 +1584,19 @@ static void outliner_draw_tree_element(
glDisable(GL_BLEND);
/* name */
- if (active == OL_DRAWSEL_NORMAL) UI_ThemeColor(TH_TEXT_HI);
- else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
- else UI_ThemeColor(TH_TEXT);
-
- UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ if ((tselem->flag & TSE_TEXTBUT) == 0) {
+ if (active == OL_DRAWSEL_NORMAL) {
+ UI_ThemeColor(TH_TEXT_HI);
+ }
+ else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
+ }
+ else {
+ UI_ThemeColor(TH_TEXT);
+ }
+
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ }
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 2627b978b40..07608b59d2e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -29,17 +29,23 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
+#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BLI_mempool.h"
+#include "BLI_stack.h"
+#include "BLI_string.h"
#include "BLT_translation.h"
@@ -47,7 +53,10 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#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"
#include "BKE_report.h"
@@ -55,6 +64,8 @@
#include "BKE_material.h"
#include "BKE_group.h"
+#include "../blenloader/BLO_readfile.h"
+
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -70,6 +81,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "GPU_material.h"
#include "outliner_intern.h"
@@ -230,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
@@ -291,64 +306,315 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Library delete --------------------------------------------------- */
+/* ID delete --------------------------------------------------- */
-static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
- Library *lib = (Library *)tselem->id;
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ Main *bmain = CTX_data_main(C);
+ ID *id = tselem->id;
- BLI_assert(te->idcode == ID_LI && lib != NULL);
+ BLI_assert(te->idcode != 0 && id != NULL);
+ BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
- /* We simply set all ID from given lib (including lib itself) to zero user count.
- * It is not possible to do a proper cleanup without a save/reload in current master. */
- a = set_listbasepointers(CTX_data_main(C), lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id;
-
- for (id = lb->first; id; id = id->next) {
- if (id->lib == lib) {
- id_fake_user_clear(id);
- id->us = 0;
+ 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, ReportList *reports, Scene *UNUSED(scene),
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ id_delete(C, reports, te, tselem);
+}
+
+static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+{
+ if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (te->idcode != 0 && tselem->id) {
+ if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ id_delete(C, reports, te, tselem);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ for (te = te->subtree.first; te; te = te->next) {
+ int ret;
+ if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_id_delete(wmOperatorType *ot)
+{
+ ot->name = "Delete Datablock";
+ ot->idname = "OUTLINER_OT_id_delete";
+ ot->description = "Delete the ID under cursor";
+
+ ot->invoke = outliner_id_delete_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* ID remap --------------------------------------------------- */
+
+static int outliner_id_remap_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
+ ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"));
+ ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
+
+ /* check for invalid states */
+ if (soops == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
+ old_id->name, new_id->name);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (old_id->lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
+ old_id->name);
+ }
+
+ BKE_libblock_remap(bmain, old_id, new_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y)
+{
+ TreeElement *te;
+
+ for (te = tree->first; te; te = te->next) {
+ if (y > te->ys && y < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && tselem->id) {
+ printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
+
+ RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
+ RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
+ return true;
}
}
+ if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ float fmval[2];
+
+ if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]);
}
- BKE_reportf(reports, RPT_WARNING,
- "Please save and reload .blend file to complete deletion of '%s' library",
- ((Library *)tselem->id)->filepath);
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
+}
+
+static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem item_tmp = {0}, *item = NULL;
+ int totitem = 0;
+ int i = 0;
+
+ short id_type = (short)RNA_enum_get(ptr, "id_type");
+ ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+
+ for (; id; id = id->next) {
+ item_tmp.identifier = item_tmp.name = id->name + 2;
+ item_tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OUTLINER_OT_id_remap(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Outliner ID data Remap";
+ ot->idname = "OUTLINER_OT_id_remap";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = outliner_id_remap_invoke;
+ ot->exec = outliner_id_remap_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+
+ prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+
+ ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0,
+ "New ID", "New ID to remap all selected IDs' users to");
+ RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
-void lib_delete_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+void id_remap_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- lib_delete(C, te, tselem, CTX_wm_reports(C));
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
+ PointerRNA op_props;
+
+ BLI_assert(tselem->id != NULL);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+
+ WM_operator_properties_free(&op_props);
+}
+
+/* Library relocate/reload --------------------------------------------------- */
+
+static int lib_relocate(
+ bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
+{
+ PointerRNA op_props;
+ int ret = 0;
+
+ BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ UNUSED_VARS_NDEBUG(te);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_string_set(&op_props, "library", tselem->id->name + 2);
+
+ if (reload) {
+ Library *lib = (Library *)tselem->id;
+ char dir[FILE_MAXDIR], filename[FILE_MAX];
+
+ BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename));
+
+ printf("%s, %s\n", tselem->id->name, lib->filepath);
+
+ /* We assume if both paths in lib are not the same then lib->name was relative... */
+ RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0);
+
+ RNA_string_set(&op_props, "directory", dir);
+ RNA_string_set(&op_props, "filename", filename);
+
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ }
+ else {
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+ }
+
+ WM_operator_properties_free(&op_props);
+
+ return ret;
}
-static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+static int outliner_lib_relocate_invoke_do(
+ bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->idcode == ID_LI && tselem->id) {
- if (((Library *)tselem->id)->parent) {
+ if (((Library *)tselem->id)->parent && !reload) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
- "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
return OPERATOR_CANCELLED;
}
+ else {
+ wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false);
- lib_delete(C, te, tselem, reports);
- return OPERATOR_FINISHED;
+ return lib_relocate(C, te, tselem, ot, reload);
+ }
}
}
else {
for (te = te->subtree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) {
return ret;
}
}
@@ -357,7 +623,51 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE
return 0;
}
-static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
+{
+ ot->name = "Relocate Library";
+ ot->idname = "OUTLINER_OT_lib_relocate";
+ ot->description = "Relocate the library under cursor";
+
+ ot->invoke = outliner_lib_relocate_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* 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, 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);
+
+ lib_relocate(C, te, tselem, ot, false);
+}
+
+
+static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -371,7 +681,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
for (te = soops->tree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
return ret;
}
}
@@ -379,16 +689,25 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
-void OUTLINER_OT_lib_delete(wmOperatorType *ot)
+void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
- ot->name = "Delete Library";
- ot->idname = "OUTLINER_OT_lib_delete";
- ot->description = "Delete the library under cursor (needs a save/reload)";
+ ot->name = "Reload Library";
+ ot->idname = "OUTLINER_OT_lib_reload";
+ ot->description = "Reload the library under cursor";
- ot->invoke = outliner_lib_delete_invoke;
+ ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
}
+void lib_reload_cb(
+ 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);
+
+ lib_relocate(C, te, tselem, ot, true);
+}
+
/* ************************************************************** */
/* Setting Toggling Operators */
@@ -468,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;
@@ -484,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);
@@ -523,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;
@@ -534,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);
@@ -571,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;
@@ -582,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);
@@ -2079,36 +2404,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
}
-
-/******** Utils to clear any ref to freed ID... **********/
-
-void ED_outliner_id_unref(SpaceOops *so, const ID *id)
-{
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(id)) {
- return; /* ID type is not used by outilner... */
- }
-
- if (so->search_tse.id == id) {
- so->search_tse.id = NULL;
- }
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == id) {
- tselem->id = NULL;
- changed = true;
- }
- }
- if (so->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- so->storeflag |= SO_TREESTORE_REBUILD;
- }
- }
-}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index dc81be7a8e0..d2666cd0b6d 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -153,35 +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 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 ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void lib_delete_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+void id_delete_cb(
+ 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 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);
@@ -190,8 +213,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
void OUTLINER_OT_item_openclose(struct wmOperatorType *ot);
void OUTLINER_OT_item_rename(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_relocate(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_reload(struct wmOperatorType *ot);
-void OUTLINER_OT_lib_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_id_delete(struct wmOperatorType *ot);
void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
@@ -230,6 +255,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 720cfe12567..776717c8443 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -47,13 +47,15 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_select_border);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
- WM_operatortype_append(OUTLINER_OT_lib_delete);
WM_operatortype_append(OUTLINER_OT_operation);
WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_lib_operation);
+ WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
+ WM_operatortype_append(OUTLINER_OT_id_delete);
+ WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 83677b6bd86..bfec62997e1 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -57,6 +57,8 @@
#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"
#include "BKE_scene.h"
@@ -133,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;
@@ -180,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;
@@ -217,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;
@@ -230,12 +235,14 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_group_unlink(bmain, group);
+ 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;
@@ -246,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;
@@ -258,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);
}
}
}
@@ -352,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;
@@ -364,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);
@@ -375,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;
@@ -387,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);
@@ -408,8 +431,9 @@ 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 the ID type has no special local function,
@@ -421,32 +445,36 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t
}
}
-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;
@@ -462,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;
@@ -480,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;
@@ -506,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;
@@ -521,10 +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 *C, Scene *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;
@@ -541,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);
}
/* ******************************************** */
@@ -565,7 +595,7 @@ void outliner_do_object_operation(
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_animdata_free(tselem->id);
+ BKE_animdata_free(tselem->id, true);
}
@@ -792,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;
@@ -805,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;
@@ -830,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;
@@ -849,6 +892,7 @@ enum {
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
+ OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -862,6 +906,8 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
+ {OL_OP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead a new chosen one"},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
@@ -885,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);
}
@@ -895,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);
}
@@ -903,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
@@ -922,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);
@@ -931,27 +977,31 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_REMAP) {
+ 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 {
@@ -988,6 +1038,8 @@ typedef enum eOutliner_PropGroupOps {
OL_GROUPOP_UNLINK = 1,
OL_GROUPOP_LOCAL,
OL_GROUPOP_LINK,
+ OL_GROUPOP_DELETE,
+ OL_GROUPOP_REMAP,
OL_GROUPOP_INSTANCE,
OL_GROUPOP_TOGVIS,
OL_GROUPOP_TOGSEL,
@@ -999,6 +1051,9 @@ static EnumPropertyItem prop_group_op_types[] = {
{OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
{OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
{OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"},
+ {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
{OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
{OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
@@ -1021,38 +1076,41 @@ 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;
+ case OL_GROUPOP_DELETE:
+ 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, 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);
}
- if (event == 3) { /* instance */
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(CTX_data_main(C));
- }
-
ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
@@ -1085,6 +1143,8 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_SINGLE,
+ OUTLINER_IDOP_DELETE,
+ OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_FAKE_ADD,
OUTLINER_IDOP_FAKE_CLEAR,
@@ -1098,6 +1158,9 @@ static EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
+ {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
+ {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
"Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
@@ -1127,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");
@@ -1159,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;
}
@@ -1168,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");
@@ -1187,10 +1250,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
+ case OUTLINER_IDOP_DELETE:
+ {
+ if (idlevel > 0) {
+ 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, 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");
@@ -1199,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");
@@ -1208,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;
@@ -1258,13 +1335,16 @@ typedef enum eOutlinerLibOpTypes {
OL_LIB_RENAME,
OL_LIB_DELETE,
+ OL_LIB_RELOCATE,
+ OL_LIB_RELOAD,
} eOutlinerLibOpTypes;
static EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
- {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"},
+ {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"},
+ {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"},
+ {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"},
{0, NULL, 0, NULL, NULL}
-
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -1286,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");
@@ -1294,13 +1374,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
case OL_LIB_DELETE:
{
- /* delete */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL);
-
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- /* Note: no undo possible here really, not 100% sure why...
- * Probably because of library optimizations in undo/redo process? */
- /* ED_undo_push(C, "Rename"); */
+ 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, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOAD:
+ {
+ /* rename */
+ 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/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 1dd66366e5d..76bf9c701ed 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -486,6 +486,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)soutlinern;
}
+static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceOops *so = (SpaceOops *)slink;
+
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(old_id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == old_id) {
+ so->search_tse.id = new_id;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == old_id) {
+ tselem->id = new_id;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
+
/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
@@ -502,7 +535,8 @@ void ED_spacetype_outliner(void)
st->operatortypes = outliner_operatortypes;
st->keymap = outliner_keymap;
st->dropboxes = outliner_dropboxes;
-
+ st->id_remap = outliner_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9c2d115108d..adb7cf4940c 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -593,7 +593,6 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f
ymid1 = (y2 - y1) * 0.25f + y1;
ymid2 = (y2 - y1) * 0.65f + y1;
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; }
@@ -840,25 +839,25 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
else
UI_GetColorPtrShade3ubv(col, col, outline_tint);
- glColor3ubv((GLubyte *)col);
-
+ if ((seq->type == SEQ_TYPE_META) ||
+ ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
+ {
+ drawmeta_contents(scene, seq, x1, y1, x2, y2);
+ }
+
if (seq->flag & SEQ_MUTE) {
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x8888);
}
+ glColor3ubv((GLubyte *)col);
+
UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
if (seq->flag & SEQ_MUTE) {
glDisable(GL_LINE_STIPPLE);
}
- if ((seq->type == SEQ_TYPE_META) ||
- ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
- {
- drawmeta_contents(scene, seq, x1, y1, x2, y2);
- }
-
/* calculate if seq is long enough to print a name */
x1 = seq->startdisp + handsize_clamped;
x2 = seq->enddisp - handsize_clamped;
@@ -1630,7 +1629,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
// NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30...
UI_view2d_constant_grid_draw(v2d);
- if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ /* Only draw backdrop in pure sequence view. */
+ if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) {
draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true);
UI_view2d_view_ortho(v2d);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 3c2a66cd3af..48c49f36471 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -107,6 +107,7 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
break;
case SEQ_SIDE_BOTH:
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
break;
}
}
@@ -812,7 +813,7 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
seq->flag |= SEQ_RIGHTSEL;
break;
case SEQ_SIDE_BOTH:
- seq->flag |= SEQ_LEFTSEL + SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
break;
}
}
@@ -942,16 +943,26 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot)
/* ****** Selected Grouped ****** */
+enum {
+ SEQ_SELECT_GROUP_TYPE,
+ SEQ_SELECT_GROUP_TYPE_BASIC,
+ SEQ_SELECT_GROUP_TYPE_EFFECT,
+ SEQ_SELECT_GROUP_DATA,
+ SEQ_SELECT_GROUP_EFFECT,
+ SEQ_SELECT_GROUP_EFFECT_LINK,
+ SEQ_SELECT_GROUP_OVERLAP,
+};
+
static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
- {1, "TYPE", 0, "Type", "Shared strip type"},
- {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
- {3, "TYPE_EFFECT", 0, "Effect Type",
+ {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
+ {SEQ_SELECT_GROUP_TYPE_BASIC, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
+ {SEQ_SELECT_GROUP_TYPE_EFFECT, "TYPE_EFFECT", 0, "Effect Type",
"Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
- {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
- {5, "EFFECT", 0, "Effect", "Shared effects"},
- {6, "EFFECT_LINK", 0, "Effect/Linked",
+ {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
+ {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
+ {SEQ_SELECT_GROUP_EFFECT_LINK, "EFFECT_LINK", 0, "Effect/Linked",
"Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
- {7, "OVERLAP", 0, "Overlap", "Overlapping time"},
+ {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
{0, NULL, 0, NULL, NULL}
};
@@ -961,14 +972,16 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
-static bool select_grouped_type(Editing *ed, Sequence *actseq)
+#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
+
+static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == actseq->type) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
}
@@ -978,7 +991,7 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -986,7 +999,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -996,7 +1009,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1004,7 +1017,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -1014,7 +1027,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq)
+static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1026,7 +1039,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
if (SEQ_HAS_PATH(actseq) && dir) {
SEQP_BEGIN (ed, seq)
{
- if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1037,7 +1050,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
Scene *sce = actseq->scene;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
}
@@ -1048,7 +1061,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
MovieClip *clip = actseq->clip;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
seq->flag |= SELECT;
changed = true;
}
@@ -1059,7 +1072,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
struct Mask *mask = actseq->mask;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
}
@@ -1070,7 +1083,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1082,7 +1095,9 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if ((seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
+ ELEM(actseq, seq->seq1, seq->seq2, seq->seq3))
+ {
effects[seq->type] = true;
}
}
@@ -1090,7 +1105,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (effects[seq->type]) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) seq->seq1->flag |= SELECT;
if (seq->seq2) seq->seq2->flag |= SELECT;
if (seq->seq3) seq->seq3->flag |= SELECT;
@@ -1119,7 +1134,7 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq = NULL;
bool changed = false;
@@ -1143,7 +1158,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
/* Ignore all seqs already selected! */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
- if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
+ if (!SEQ_CHANNEL_CHECK(seq, channel) ||
+ (seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
(!is_audio && SEQ_IS_SOUND(seq)) ||
(is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq))))
{
@@ -1189,17 +1205,19 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
- int type = RNA_enum_get(op->ptr, "type");
- bool changed = false, extend;
- extend = RNA_boolean_get(op->ptr, "extend");
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ bool changed = false;
if (actseq == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
- if (extend == 0) {
+ if (!extend) {
SEQP_BEGIN (ed, seq)
{
seq->flag &= ~SELECT;
@@ -1208,13 +1226,32 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
SEQ_END;
}
- if (type == 1) changed |= select_grouped_type(ed, actseq);
- else if (type == 2) changed |= select_grouped_type_basic(ed, actseq);
- else if (type == 3) changed |= select_grouped_type_effect(ed, actseq);
- else if (type == 4) changed |= select_grouped_data(ed, actseq);
- else if (type == 5) changed |= select_grouped_effect(ed, actseq);
- else if (type == 6) changed |= select_grouped_effect_link(ed, actseq);
- else if (type == 7) changed |= select_grouped_time_overlap(ed, actseq);
+ switch (type) {
+ case SEQ_SELECT_GROUP_TYPE:
+ changed |= select_grouped_type(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_BASIC:
+ changed |= select_grouped_type_basic(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_EFFECT:
+ changed |= select_grouped_type_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_DATA:
+ changed |= select_grouped_data(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT:
+ changed |= select_grouped_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT_LINK:
+ changed |= select_grouped_effect_link(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_OVERLAP:
+ changed |= select_grouped_time_overlap(ed, actseq);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
@@ -1240,7 +1277,9 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
+ RNA_def_boolean(ot->srna, "use_active_channel", false, "Same Channel",
+ "Only consider strips on the same channel as the active one");
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index fce40f8ca59..a2a80297041 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -41,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_global.h"
@@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS
break;
}
}
+
+static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceSeq *sseq = (SpaceSeq *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)sseq->gpd == old_id) {
+ sseq->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* ************************************* */
/* only called once, from space/spacetypes.c */
@@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void)
st->dropboxes = sequencer_dropboxes;
st->refresh = sequencer_refresh;
st->listener = sequencer_listener;
+ st->id_remap = sequencer_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 0a6a9a81e63..686a10fc785 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_text.h"
@@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar)
}
}
+static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceText *stext = (SpaceText *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_TXT)) {
+ return;
+ }
+
+ if ((ID *)stext->text == old_id) {
+ stext->text = (Text *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/********************* registration ********************/
/* only called once, from space/spacetypes.c */
@@ -582,7 +597,8 @@ void ED_spacetype_text(void)
st->listener = text_listener;
st->context = text_context;
st->dropboxes = text_dropboxes;
-
+ st->id_remap = text_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 04cff288b03..c38c57b9528 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -259,10 +259,8 @@ static void confirm_suggestion(Text *text)
// for (i = 0; i < skipleft; i++)
// txt_move_left(text, 0);
- for (i = 0; i < over; i++)
- txt_move_left(text, 1);
-
- txt_insert_buf(text, sel->name);
+ BLI_assert(memcmp(sel->name, &line[i], over) == 0);
+ txt_insert_buf(text, sel->name + over);
// for (i = 0; i < skipleft; i++)
// txt_move_right(text, 0);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index d404e7aaf15..94ed280f792 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
+ BKE_libblock_delete(bmain, text);
text_drawcache_tag_update(st, 1);
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 9872b05da63..cf738de0202 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -130,7 +130,6 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
- glShadeModel(GL_SMOOTH);
glBegin(GL_LINE_STRIP);
for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
@@ -187,7 +186,6 @@ void draw_motion_path_instance(Scene *scene,
}
glEnd();
- glShadeModel(GL_FLAT);
glPointSize(1.0);
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index f7c1e2ee981..1d9a515a5f2 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -431,10 +431,9 @@ static void draw_bonevert_solid(void)
glNewList(displist, GL_COMPILE);
qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ /* Draw tips of a bone */
gluSphere(qobj, 0.05, 8, 5);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -890,7 +889,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
}
else {
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
@@ -968,7 +966,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* restore */
if (dt == OB_SOLID) {
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -986,10 +983,11 @@ static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38};
static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id,
bPoseChannel *pchan, EditBone *ebone)
{
+ /* call this once, avoid constant changing */
+ BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1);
+
float length;
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
if (pchan)
length = pchan->bone->length;
else
@@ -1769,7 +1767,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* and draw blended distances */
if (arm->flag & ARM_POSEMODE) {
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -1792,7 +1789,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
}
@@ -2216,7 +2212,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* and draw blended distances */
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -2231,7 +2226,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
/* if solid we draw it first */
@@ -2699,6 +2693,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->flag2 & V3D_RENDER_OVERRIDE)
return true;
+ /* needed for 'draw_line_bone' which draws pixel. */
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ }
+
if (dt > OB_WIRE) {
/* we use color for solid lighting */
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2774,5 +2773,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* restore */
glFrontFace(GL_CCW);
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ }
+
return retval;
}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 0bc6447d028..755d4985518 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -369,15 +369,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
}
if (c_badtex) lit = 0;
- if (lit != c_lit || ma != c_ma) {
- if (lit) {
- int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR;
+ if (lit != c_lit || ma != c_ma || textured != c_textured) {
+ int options = GPU_SHADER_USE_COLOR;
- if (gtexdraw.two_sided_lighting)
- options |= GPU_SHADER_TWO_SIDED;
- if (c_textured && !c_badtex)
- options |= GPU_SHADER_TEXTURE_2D;
+ if (c_textured && !c_badtex) {
+ options |= GPU_SHADER_TEXTURE_2D;
+ }
+ if (gtexdraw.two_sided_lighting) {
+ options |= GPU_SHADER_TWO_SIDED;
+ }
+ if (lit) {
+ options |= GPU_SHADER_LIGHTING;
if (!ma)
ma = give_current_material_or_def(NULL, 0); /* default material */
@@ -385,12 +388,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
mul_v3_v3fl(specular, &ma->specr, ma->spec);
GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f);
- GPU_basic_shader_bind(options);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
+ GPU_basic_shader_bind(options);
+
c_lit = lit;
c_ma = ma;
}
@@ -495,7 +496,6 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
- glShadeModel(GL_SMOOTH);
glCullFace(GL_BACK);
}
@@ -527,7 +527,6 @@ static void draw_textured_end(void)
GPU_set_tpage(NULL, 0, 0);
}
- glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -980,10 +979,17 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
if (ob == OBACT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN;
-
}
else if (ob->mode & OB_MODE_SCULPT) {
- dm_draw_flag |= DM_DRAW_SKIP_HIDDEN;
+ dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS;
+ }
+ else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
+ }
+ }
+ else {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
}
}
@@ -1311,8 +1317,8 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
}
glColor4ub(255, 255, 255, 96);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data);
@@ -1324,7 +1330,7 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
glEnable(GL_DEPTH_TEST);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
if (use_alpha) {
glDisable(GL_BLEND);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 5768a37a0d9..acc20997b27 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -1209,7 +1209,7 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
return;
}
@@ -1409,8 +1409,8 @@ static void drawlamp(Scene *scene, 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);
}
@@ -1600,12 +1600,9 @@ static void draw_bundle_sphere(void)
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
-
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
gluSphere(qobj, 0.05, 8, 8);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1787,8 +1784,6 @@ static void draw_viewport_reconstruction(
GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- glShadeModel(GL_SMOOTH);
-
tracking_object = tracking->objects.first;
while (tracking_object) {
draw_viewport_object_reconstruction(
@@ -1799,7 +1794,6 @@ static void draw_viewport_reconstruction(
}
/* restore */
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1938,16 +1932,15 @@ static void drawcamera_stereo3d(
if (is_stereo3d_cameras) {
/* draw connecting lines */
- glPushAttrib(GL_ENABLE_BIT);
-
- glLineStipple(2, 0xAAAA);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(2, 0xAAAA);
glBegin(GL_LINES);
glVertex3fv(origin[0]);
glVertex3fv(origin[1]);
glEnd();
- glPopAttrib();
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
/* draw convergence plane */
@@ -2359,7 +2352,6 @@ static void drawlattice(View3D *v3d, Object *ob)
if (ob->defbase.first && lt->dvert) {
actdef_wcol = ob->actdef;
- glShadeModel(GL_SMOOTH);
}
}
@@ -2388,10 +2380,6 @@ static void drawlattice(View3D *v3d, Object *ob)
}
}
glEnd();
-
- /* restoration for weight colors */
- if (actdef_wcol)
- glShadeModel(GL_FLAT);
if (is_edit) {
BPoint *actbp = BKE_lattice_active_point_get(lt);
@@ -3256,17 +3244,15 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
{
if (draw_dm_edges_weight_check(me, v3d)) {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex weights
draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
- glShadeModel(GL_FLAT);
}
else if (ts->selectmode == SCE_SELECT_FACE) {
draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex selection
draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
- glShadeModel(GL_FLAT);
}
}
else {
@@ -3766,7 +3752,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
- /* pass */
+ /* pass */
}
else {
/* annoying but active faces is stored differently */
@@ -4272,12 +4258,15 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
if (ob == obedit || drawlinked) {
DerivedMesh *finalDM, *cageDM;
- if (obedit != ob)
- finalDM = cageDM = editbmesh_get_derived_base(ob, em);
- else
+ if (obedit != ob) {
+ finalDM = cageDM = editbmesh_get_derived_base(
+ ob, em, scene->customdata_mask);
+ }
+ else {
cageDM = editbmesh_get_derived_cage_and_final(
scene, ob, em, scene->customdata_mask,
&finalDM);
+ }
const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0);
@@ -4469,10 +4458,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
glEnableClientState(GL_VERTEX_ARRAY);
- if (ob->type == OB_MBALL) { /* mball always smooth shaded */
- glShadeModel(GL_SMOOTH);
- }
-
/* track current material, -1 for none (needed for lines) */
short col = -1;
@@ -4494,7 +4479,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
// glVertexPointer(3, GL_FLOAT, 0, dl->verts);
// glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
-
glBegin(GL_LINE_STRIP);
for (int nr = dl->nr; nr; nr--, data += 3)
glVertex3fv(data);
@@ -4525,15 +4509,15 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
col = dl->col;
}
-
- if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
- else glShadeModel(GL_FLAT);
+ /* FLAT/SMOOTH shading for surfaces */
+ glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, dl->verts);
glNormalPointer(GL_FLOAT, 0, dl->nors);
glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
glDisableClientState(GL_NORMAL_ARRAY);
+ glShadeModel(GL_SMOOTH);
}
break;
@@ -4578,7 +4562,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
}
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
glFrontFace(GL_CCW);
if (col != -1) {
@@ -5043,7 +5026,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
unsigned char tcol[4] = {0, 0, 0, 255};
/* 1. */
- if (part == NULL || !psys_check_enabled(ob, psys))
+ if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
return;
if (pars == NULL) return;
@@ -5751,7 +5734,7 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit
/* create path and child path cache if it doesn't exist already */
if (edit->pathcache == NULL)
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
}
static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
@@ -5788,8 +5771,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- glShadeModel(GL_SMOOTH);
-
if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
@@ -5904,7 +5885,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -8247,7 +8227,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8272,7 +8252,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8291,7 +8271,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8305,7 +8285,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
}
/**
- * dont set #WM_framebuffer_index_set. just use to mask other
+ * dont set #GPU_framebuffer_index_set. just use to mask other
*/
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
@@ -8324,7 +8304,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8337,7 +8317,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
glVertex3fv(cent);
}
@@ -8368,7 +8348,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
{
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
@@ -8377,7 +8357,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
Mesh *me = userData;
if (!(me->mpoly[index].flag & ME_HIDE)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8385,7 +8365,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
}
}
-/* must have called WM_framebuffer_index_set beforehand */
+/* must have called GPU_framebuffer_index_set beforehand */
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
{
Mesh *me = userData;
@@ -8511,7 +8491,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
DerivedMesh *dm = NULL, *edm = NULL;
if (ob->mode & OB_MODE_EDIT) {
- edm = editbmesh_get_derived_base(ob, me->edit_btmesh);
+ edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH);
DM_update_materials(edm, ob);
}
else {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 470fa80bb71..0805b81147f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1472,6 +1472,66 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return -1; /* found but not available */
}
+static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ View3D *v3d;
+ ARegion *ar;
+ bool is_local = false;
+
+ if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
+ return;
+ }
+
+ for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
+ if ((ID *)v3d->camera == old_id) {
+ v3d->camera = (Object *)new_id;
+ if (!new_id) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
+ }
+ }
+ }
+ }
+ }
+ if ((ID *)v3d->ob_centre == old_id) {
+ v3d->ob_centre = (Object *)new_id;
+ if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */
+ v3d->ob_centre_bone[0] = '\0';
+ }
+ }
+
+ if ((ID *)v3d->defmaterial == old_id) {
+ v3d->defmaterial = (Material *)new_id;
+ }
+#if 0 /* XXX Deprecated? */
+ if ((ID *)v3d->gpd == old_id) {
+ v3d->gpd = (bGPData *)new_id;
+ }
+#endif
+
+ if (ELEM(GS(old_id->name), ID_IM, ID_MC)) {
+ for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if ((ID *)bgpic->ima == old_id) {
+ bgpic->ima = (Image *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ if ((ID *)bgpic->clip == old_id) {
+ bgpic->clip = (MovieClip *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+ }
+
+ if (is_local) {
+ break;
+ }
+ }
+}
/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
@@ -1491,7 +1551,8 @@ void ED_spacetype_view3d(void)
st->keymap = view3d_keymap;
st->dropboxes = view3d_dropboxes;
st->context = view3d_context;
-
+ st->id_remap = view3d_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 9fe4f1cc283..62059766bd6 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -659,7 +659,6 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glShadeModel(GL_SMOOTH);
glPointSize(5);
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
@@ -1491,7 +1490,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
BLI_endian_switch_uint32(&col);
}
- return WM_framebuffer_to_index(col);
+ return GPU_select_to_index(col);
}
/* reads full rect, converts indices */
@@ -1524,7 +1523,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
IMB_convert_rgba_to_abgr(ibuf_clip);
}
- WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
if ((clip.xmin == xmin) &&
(clip.xmax == xmax) &&
@@ -3399,17 +3398,15 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
}
}
-
+ // Draw world
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glEnd();
- glShadeModel(GL_FLAT);
if (v3d->flag3 & V3D_SHOW_WORLD_DIFFUSE) {
GPU_probe_sh_shader_unbind();
@@ -3460,8 +3457,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glPushMatrix();
glLoadIdentity();
- glShadeModel(GL_SMOOTH);
-
/* calculate buffers the first time only */
if (!buf_calculated) {
for (x = 0; x < VIEWGRAD_RES_X; x++) {
@@ -3547,8 +3542,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
- glShadeModel(GL_FLAT);
-
#undef VIEWGRAD_RES_X
#undef VIEWGRAD_RES_Y
}
@@ -3577,7 +3570,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
UI_ThemeColor(TH_LOW_GRAD);
glVertex3f(-1.0, -1.0, 1.0);
@@ -3586,8 +3578,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glEnd();
- glShadeModel(GL_FLAT);
-
glDepthFunc(GL_LEQUAL);
glDisable(GL_DEPTH_TEST);
@@ -4506,6 +4496,10 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
v3d->flag |= V3D_INVALID_BACKBUF;
+
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp));
}
#ifdef DEBUG_DRAW
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 155c7503acf..1bd0ec23d65 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3620,7 +3620,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
dist_range[0] = v3d->near * 1.5f;
}
else { /* othographic */
- /* find the current window width and height */
+ /* find the current window width and height */
vb[0] = ar->winx;
vb[1] = ar->winy;
@@ -4911,7 +4911,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
* Get the world-space 3d location from a screen-space 2d point.
*
* \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space loction.
+ * \param mouse_worldloc: Output world-space location.
* \param fallback_depth_pt: Use this points depth when no depth can be found.
*/
bool ED_view3d_autodist(
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 797d97586c7..ac05853e6d0 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -302,8 +302,9 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
+static void view3d_win_to_ray_segment(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
{
RegionView3D *rv3d = ar->regiondata;
float _ray_co[3], _ray_dir[3], start_offset, end_offset;
@@ -346,7 +347,7 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
}
}
-BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3])
+BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
{
if ((rv3d->rflag & RV3D_CLIPPING) &&
(clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
@@ -373,8 +374,9 @@ BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], floa
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
+bool ED_view3d_win_to_ray_ex(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
{
float ray_end[3];
@@ -382,7 +384,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end);
+ return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
}
return true;
@@ -401,8 +403,9 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
+bool ED_view3d_win_to_ray(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
{
return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
}
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index c6951c79609..f46608b7d5e 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -259,6 +259,37 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
}
}
+/**
+ * Ensure the 'snap_context' is only cached while dragging,
+ * needed since the user may toggle modes between tool use.
+ */
+static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+{
+ if (state == ruler_info->state) {
+ return;
+ }
+
+ /* always remove */
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ ruler_info->snap_context = NULL;
+ }
+
+ if (state == RULER_STATE_NORMAL) {
+ /* pass */
+ }
+ else if (state == RULER_STATE_DRAG) {
+ ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ ruler_info->ar, CTX_wm_view3d(C));
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ ruler_info->state = state;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
{
@@ -640,7 +671,9 @@ static void view3d_ruler_free(RulerInfo *ruler_info)
{
BLI_freelistN(&ruler_info->items);
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ }
MEM_freeN(ruler_info);
}
@@ -757,10 +790,6 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
- ar, CTX_wm_view3d(C));
-
ruler_info->win = win;
ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
@@ -818,7 +847,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_info->snap_flag &= ~RULER_SNAP_OK;
do_draw = true;
}
- ruler_info->state = RULER_STATE_NORMAL;
+ ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
}
}
else {
@@ -835,7 +864,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info);
RulerItem *ruler_item;
/* check if we want to drag an existing point or add a new one */
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
ruler_item = ruler_item_add(ruler_info);
ruler_item_active_set(ruler_info, ruler_item);
@@ -877,7 +906,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
ruler_item_pick->co_index = 1;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -904,7 +933,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->co_index = co_index;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bedcf413bfa..a460d8900b4 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -94,6 +94,8 @@
#include "UI_interface.h"
+#include "GPU_draw.h"
+
#include "view3d_intern.h" /* own include */
float ED_view3d_select_dist_px(void)
@@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 5b1a58497f0..95864474fc0 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -4144,7 +4153,12 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
r_snap[2] = r_snap[1] * 0.1f;
}
}
- else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ else if (t->spacetype == SPACE_IMAGE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.0625f;
+ r_snap[2] = 0.03125f;
+ }
+ else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = 0.0f;
r_snap[1] = 0.125f;
r_snap[2] = 0.0625f;
@@ -5361,7 +5375,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);
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 0e0d085bf6f..50168e78dda 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -592,6 +592,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fa5e86813fa..707c60f8701 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2676,6 +2676,20 @@ void flushTransSeq(TransInfo *t)
BKE_sequence_calc(t->scene, seq);
}
}
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
+ a < t->total;
+ a++, td++, td2d++, seq_prev = seq)
+ {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
}
/* need to do the overlap check in a new loop otherwise adjacent strips
@@ -4920,44 +4934,47 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
break;
}
- seq_prev = seq;
}
if (overlap) {
- bool has_effect = false;
+ bool has_effect_root = false, has_effect_any = false;
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect = true;
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
}
else {
- /* Tag seq with a non zero value, used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- seq->tmp = (void *)1;
+ /* Tag seq with a non zero value,
+ * used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
}
}
+
}
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
}
}
@@ -4989,11 +5006,10 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
BKE_sequence_base_shuffle_time(seqbasep, t->scene);
}
- if (has_effect) {
+ if (has_effect_any) {
/* update effects strips based on strips just moved in time */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5001,13 +5017,14 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
}
}
+ }
+ if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
if (BKE_sequence_test_overlap(seqbasep, seq)) {
BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
@@ -5874,6 +5891,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
if (t->flag & T_MIRROR) {
TransData *td;
@@ -5897,8 +5915,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
EDBM_automerge(t->scene, t->obedit, true, hflag);
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_select_flush(em);
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
}
}
}
@@ -7587,7 +7607,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
if (pcp->bez.f2 & SELECT) {
td += 3;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 5d49d1d9315..6e399d9fde3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
@@ -686,7 +687,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Tilt";
- /* optionals -
+ /* optional -
* "Tilt selected vertices"
* "Specify an extra axis rotation for selected vertices of 3D curve" */
ot->description = "Tilt selected control vertices of 3D curve";
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 59d2485c964..90a4aa3614d 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -636,7 +636,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_face_calc_plane(efa, vec);
+ BM_face_calc_tangent_auto(efa, vec);
add_v3_v3(normal, efa->no);
add_v3_v3(plane, vec);
}
@@ -690,7 +690,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
}
else {
- BM_vert_tri_calc_plane(v_tri, plane);
+ BM_vert_tri_calc_tangent_edge(v_tri, plane);
}
}
else {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index e1cf7436236..0bb64315845 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -599,15 +599,15 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- G.main, t->scene, SNAP_OBJECT_USE_CACHE,
- t->ar, t->view);
+ G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
- t->tsnap.object_context,
- (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
- bm_edge_is_snap_target,
- bm_face_is_snap_target,
- SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ bm_edge_is_snap_target,
+ bm_face_is_snap_target,
+ SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
}
}
@@ -842,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
vec[1] = point[1] - t->tsnap.snapTarget[1];
}
else {
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ zero_v3(point); /* no good answer here... */
+ }
+ }
+ }
+
sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
}
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index d7486372c36..e85b686b5b3 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;
@@ -87,8 +87,8 @@ struct SnapObjectContext {
* otherwise this doesn't take viewport into account. */
bool use_v3d;
struct {
- struct View3D *v3d;
- struct ARegion *ar;
+ const struct View3D *v3d;
+ const struct ARegion *ar;
} v3d_data;
@@ -198,7 +198,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
- /* currently unused, and causes issues when looptri's havn't been calculated.
+ /* currently unused, and causes issues when looptri's haven't been calculated.
* since theres some overhead in ensuring this data is valid, it may need to be optional. */
#if 0
if (data->dm) {
@@ -222,9 +222,12 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
* \{ */
static bool snapEdge(
- ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ 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],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3])
{
float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
@@ -312,9 +315,12 @@ static bool snapEdge(
}
static bool snapVertex(
- ARegion *ar, const float vco[3], const float vno[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ const ARegion *ar, const float vco[3], const float vno[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3])
{
bool retval = false;
@@ -362,9 +368,12 @@ static bool snapVertex(
}
static bool snapArmature(
- ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -444,9 +453,12 @@ static bool snapArmature(
}
static bool snapCurve(
- ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -481,24 +493,27 @@ static bool snapCurve(
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,
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
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,
+ ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
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,
+ ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -508,8 +523,9 @@ static bool snapCurve(
break;
}
retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -518,14 +534,16 @@ static bool snapCurve(
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,
+ ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
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,
+ ar, nu->bp[u].vec, NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local,
+ ray_depth, dist_px,
r_loc, NULL);
}
}
@@ -542,9 +560,12 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- ARegion *ar, Object *ob, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float imat[4][4];
@@ -582,9 +603,12 @@ static bool snapEmpty(
}
static bool snapCamera(
- ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
@@ -674,16 +698,166 @@ 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 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] = {
+ vco[0] * scale[0],
+ vco[1] * scale[1],
+ vco[2] * scale[2],
+ };
+ const float co_sc[3] = {
+ ray_co[0] * scale[0],
+ ray_co[1] * scale[1],
+ ray_co[2] * scale[2],
+ };
+ const float dir_sc[3] = {
+ ray_dir[0] * scale[0],
+ ray_dir[1] * scale[1],
+ ray_dir[2] * scale[2],
+ };
+
+ float depth;
+ float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth);
+
+ if (depth < ray_depth_range[0])
+ return false;
+
+ if (is_persp)
+ dist_sq /= SQUARE(depth);
+
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
+
+ copy_v3_v3(r_co, vco);
+
+ if (vno) {
+ copy_v3_v3(r_no, vno);
+ }
+
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
+
+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])
+{
+ const float v1_sc[3] = {
+ v1[0] * scale[0],
+ v1[1] * scale[1],
+ v1[2] * scale[2],
+ };
+ const float v2_sc[3] = {
+ v2[0] * scale[0],
+ v2[1] * scale[1],
+ v2[2] * scale[2],
+ };
+ const float co_sc[3] = {
+ ray_co[0] * scale[0],
+ ray_co[1] * scale[1],
+ ray_co[2] * scale[2],
+ };
+ const float dir_sc[3] = {
+ ray_dir[0] * scale[0],
+ ray_dir[1] * scale[1],
+ ray_dir[2] * scale[2],
+ };
+
+ 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);
+
+ if (depth < ray_depth_range[0])
+ return false;
+
+ if (is_persp)
+ dist_sq /= SQUARE(depth);
+
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
+
+ tmp_co[0] /= scale[0];
+ tmp_co[1] /= scale[1];
+ tmp_co[2] /= scale[2];
+
+ copy_v3_v3(r_co, tmp_co);
+
+ if (r_no) {
+ sub_v3_v3v3(r_no, v1, v2);
+ }
+
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
+
+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, 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, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (snap_to == SCE_SNAP_MODE_FACE) {
@@ -703,10 +877,8 @@ 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;
+ const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp;
+ 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 */
@@ -735,7 +907,7 @@ static bool snapDerivedMesh(
if (bb) {
BoundBox bb_temp;
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ /* We cannot afford a bounding box with some null dimension, which may happen in some cases...
* Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
@@ -772,6 +944,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 +968,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,53 +977,56 @@ 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 (treedata && treedata->tree != NULL) {
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- len_diff = sqrtf(nearest.dist_sq);
- }
- }
- }
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
-
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
{
+ /* 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 (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;
@@ -861,7 +1037,7 @@ static bool snapDerivedMesh(
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob = ob;
- data.ob_uuid = ob_index,
+ data.ob_uuid = ob_index;
data.dm = dm;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -907,40 +1083,90 @@ static bool snapDerivedMesh(
}
case SCE_SNAP_MODE_VERTEX:
{
+ 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 = local_depth * local_depth;
- if (treedata->tree &&
+ nearest.dist_sq = *dist_to_ray_sq;
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = treedata;
+ 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);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_vert_depth_cb, &userdata) :
BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_vert_depth_cb, &userdata)) != -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);
+ 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_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
}
break;
}
case SCE_SNAP_MODE_EDGE:
{
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
-
- for (int i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- retval |= snapEdge(
- ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
- obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
+ 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 = treedata;
+ 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);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_edge_depth_cb, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, test_edge_depth_cb, &userdata)) != -1)
+ {
+ 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_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
+ }
break;
}
}
@@ -955,17 +1181,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,
+ float *dist_px, 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,
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (snap_to == SCE_SNAP_MODE_FACE) {
@@ -985,31 +1245,19 @@ 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));
+ const bool is_persp = (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 +1275,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 +1292,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) {
@@ -1059,12 +1308,29 @@ static bool snapEditMesh(
em->bm, looptri_mask,
sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
}
- bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6);
+ bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
if (looptri_mask) {
MEM_freeN(looptri_mask);
}
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,43 +1351,56 @@ 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:
{
+ float ray_start_local[3];
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
+
+ /* 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;
+ }
+
+ /* 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)
+ {
+ 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;
+ }
+ }
+ }
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -1176,47 +1455,92 @@ static bool snapEditMesh(
}
break;
}
- case SCE_SNAP_MODE_VERTEX:
+ case 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 = local_depth * local_depth;
- if (treedata->tree &&
+ 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);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata) :
BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -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);
+ 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_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+
+ retval = true;
}
break;
}
- case SCE_SNAP_MODE_EDGE:
+ case SCE_SNAP_MODE_VERTEX:
{
- 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);
+ 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);
+
+ if (treedata->tree && (
+ is_persp ?
+ BLI_bvhtree_find_nearest_to_ray_angle(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmvert_depth_cb, &userdata) :
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -1)
+ {
+ 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_px *= nearest.dist_sq / (*dist_to_ray_sq);
+ *dist_to_ray_sq = nearest.dist_sq;
+ retval = true;
+ }
break;
}
}
@@ -1231,18 +1555,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 mval[2],
+ 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, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
+ const ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1251,9 +1585,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,
+ dist_px, snap_to,
+ 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 +1604,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, true,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
+ 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,
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
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,
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
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,
+ ar, ob, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
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,
+ ar, sctx->scene, ob, obmat, mval, snap_to,
+ ray_start, ray_normal,
+ ray_depth, dist_px,
r_loc, r_no);
}
@@ -1312,18 +1653,68 @@ 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 mval: Optional screen-space 2D location we're snapping to (may phase out).
+ * \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.
+ *
+ * \param dist_px: Pixel distance to element,
+ * note that this will eventually be replaced entirely by \a dist_to_ray_sq.
+ *
+ * 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 bool use_object_edit_cage, const float mval[2],
+ 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, float *dist_px,
/* 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;
@@ -1337,9 +1728,10 @@ static bool snapObjectsRay(
Object *ob = base_act->object;
retval |= snapObject(
- sctx, ob, ob->obmat, false, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob, ob->obmat, ob_index++,
+ false, snap_to, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1372,9 +1764,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, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1385,9 +1778,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, mval,
+ ray_origin, ray_start, ray_normal, ray_depth_range,
+ ray_depth, dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -1419,7 +1813,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
Main *bmain, Scene *scene, int flag,
/* extra args for view3d */
- ARegion *ar, View3D *v3d)
+ const ARegion *ar, const View3D *v3d)
{
SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
@@ -1489,15 +1883,19 @@ 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,
+ NULL,
+ ray_start, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq, NULL,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -1516,6 +1914,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;
}
@@ -1526,9 +1926,9 @@ 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,
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal,
+ &ray_depth, &dist_to_ray_sq, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1637,12 +2037,27 @@ 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.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
+ * \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
* \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.
@@ -1672,7 +2087,7 @@ bool ED_transform_snap_object_project_view3d_ex(
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index)
{
- float ray_start[3], ray_normal[3], ray_orgigin[3];
+ float ray_start[3], ray_normal[3], ray_origin[3];
float ray_depth_fallback;
if (ray_depth == NULL) {
@@ -1682,16 +2097,37 @@ bool ED_transform_snap_object_project_view3d_ex(
if (!ED_view3d_win_to_ray_ex(
sctx->v3d_data.ar, sctx->v3d_data.v3d,
- mval, ray_orgigin, ray_normal, ray_start, true))
+ mval, ray_origin, ray_normal, ray_start, true))
{
return false;
}
+ float dist_to_ray_sq;
+ {
+ float 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);
+ }
+
return snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- mval, dist_px,
- ray_start, ray_normal, ray_orgigin, ray_depth,
+ mval,
+ ray_origin, ray_start, ray_normal,
+ ray_depth, &dist_to_ray_sq, dist_px,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 1f4ce926f16..e2f60955c81 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -57,6 +57,7 @@
#include "BKE_multires.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
+#include "BKE_screen.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
/**
* Use to free ID references within runtime data (stored outside of DNA)
*
- * \note Typically notifiers take care of this,
- * but there are times we have to free references immediately, see: T44376
+ * \param new_id may be NULL to unlink \a old_id.
*/
-void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
- switch (sl->spacetype) {
- case SPACE_OUTLINER:
- ED_outliner_id_unref((SpaceOops *)sl, id);
- break;
- case SPACE_BUTS:
- ED_buttons_id_unref((SpaceButs *)sl, id);
- break;
- case SPACE_NODE:
- ED_node_id_unref((SpaceNode *)sl, id);
- break;
+ if (st && st->id_remap) {
+ st->id_remap(sa, sl, old_id, new_id);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index baa471e920b..94d69a0169f 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -279,8 +279,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
col[3] = 0.5f; /* hard coded alpha, not that nice */
- glShadeModel(GL_SMOOTH);
-
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
@@ -344,8 +342,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BLI_buffer_free(&av_buf);
BLI_buffer_free(&auv_buf);
- glShadeModel(GL_FLAT);
-
break;
}
}
@@ -794,8 +790,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
if (interpedges) {
- glShadeModel(GL_SMOOTH);
-
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -810,8 +805,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
else {
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 59f9cd16908..b3190ef784f 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -740,6 +740,16 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
{
PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
copy_v3_v3(v->co, co);
+
+ /* 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. */
+ for (int i = 0; i < 3; i++) {
+ if (UNLIKELY(!isfinite(v->co[i]))) {
+ v->co[i] = 0.0f;
+ }
+ }
+
v->u.key = key;
v->edge = e;
v->flag = 0;
@@ -3040,8 +3050,10 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
p_chart_boundaries(chart, NULL, &outer);
- if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2))
+ /* outer can be NULL with non-finite coords. */
+ if (outer && !p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) {
p_chart_extrema_verts(chart, &pin1, &pin2);
+ }
chart->u.lscm.pin1 = pin1;
chart->u.lscm.pin2 = pin2;
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/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
index 3f29d9899e8..9efbe6b53be 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
@@ -111,7 +111,7 @@ static PyObject *FrsNoise_drand(BPy_FrsNoise * /*self*/, PyObject *args, PyObjec
PyErr_SetString(PyExc_TypeError, "optional argument 1 must be of type int");
return NULL;
}
- if (seed){
+ if (seed) {
RandGen::srand48(seed);
}
return PyFloat_FromDouble(RandGen::drand48());
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/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/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 5403ec6b13b..0e08af1bac8 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -84,8 +84,7 @@ public:
Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name);
if (text) {
ok = BPY_execute_text(_context, text, reports, false);
- BKE_text_unlink(&_freestyle_bmain, text);
- BKE_libblock_free(&_freestyle_bmain, text);
+ BKE_libblock_delete(&_freestyle_bmain, text);
}
else {
BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn);
diff --git a/source/blender/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_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
index df2da971845..d9bf3d1ced3 100644
--- a/source/blender/gpu/GPU_basic_shader.h
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -46,11 +46,13 @@ typedef enum GPUBasicShaderOption {
GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */
GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */
GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */
+ GPU_SHADER_TEXTURE_RECT = (1 << 4), /* same as GPU_SHADER_TEXTURE_2D, for GL_TEXTURE_RECTANGLE */
- GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */
- GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */
- GPU_SHADER_LINE = (1 << 6), /* draw lines */
- GPU_SHADER_OPTIONS_NUM = 7,
+ GPU_SHADER_SOLID_LIGHTING = (1 << 5), /* use faster lighting (set automatically) */
+ GPU_SHADER_STIPPLE = (1 << 6), /* use stipple */
+ GPU_SHADER_LINE = (1 << 7), /* draw lines */
+ GPU_SHADER_FLAT_NORMAL = (1 << 8), /* use flat normals */
+ GPU_SHADER_OPTIONS_NUM = 9,
GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
} GPUBasicShaderOption;
@@ -74,10 +76,30 @@ void GPU_basic_shaders_init(void);
void GPU_basic_shaders_exit(void);
void GPU_basic_shader_bind(int options);
+void GPU_basic_shader_bind_enable(int options);
+void GPU_basic_shader_bind_disable(int options);
+
int GPU_basic_shader_bound_options(void);
-void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha);
+/* Only use for small blocks of code that don't support glsl shader. */
+#define GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if ((bound_options = GPU_basic_shader_bound_options())) { \
+ GPU_basic_shader_bind(0); \
+ } \
+} \
+else { bound_options = 0; } ((void)0)
+#define GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if (bound_options) { \
+ GPU_basic_shader_bind(bound_options); \
+ } \
+} ((void)0)
+
+
+void GPU_basic_shader_colors(
+ const float diffuse[3], const float specular[3],
+ int shininess, float alpha);
/* Fixed Function Lighting */
@@ -110,6 +132,9 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
void GPU_basic_shader_line_width(float line_width);
+bool GPU_basic_shader_use_glsl_get(void);
+void GPU_basic_shader_use_glsl_set(bool enabled);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index aefaf1a0f54..7972d138b9b 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -230,7 +230,7 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
const int face_indices_len);
GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
- int *grid_indices, int totgrid,unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
+ int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
struct GridCommonGPUBuffer **grid_common_gpu_buffer);
GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 10a4491d770..d5dbd55279d 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -99,8 +99,9 @@ void GPU_clear_tpage(bool force);
* - this affects fixed functions materials and texface, not glsl */
int GPU_default_lights(void);
-int GPU_scene_object_lights(struct Scene *scene, struct Object *ob,
- int lay, float viewmat[4][4], int ortho);
+int GPU_scene_object_lights(
+ struct Scene *scene, struct Object *ob,
+ int lay, float viewmat[4][4], int ortho);
/* Text render
* - based on moving uv coordinates */
@@ -135,13 +136,15 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
-int GPU_verify_image(struct Image *ima,
- struct ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap);
-void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima, bool is_envmap);
+int GPU_verify_image(
+ struct Image *ima, struct ImageUser *iuser,
+ int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap);
+void GPU_create_gl_tex(
+ unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
+ int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima, bool is_envmap);
void GPU_create_gl_tex_compressed(
- unsigned int *bind, unsigned int *pix, int x, int y, int mipmap,
- int textarget, struct Image *ima, struct ImBuf *ibuf);
+ unsigned int *bind, unsigned int *pix, int x, int y, int mipmap,
+ int textarget, struct Image *ima, struct ImBuf *ibuf);
bool GPU_upload_dxt_texture(struct ImBuf *ibuf);
void GPU_free_image(struct Image *ima);
void GPU_free_images(void);
@@ -160,6 +163,12 @@ struct DerivedMesh;
void GPU_draw_update_fvar_offset(struct DerivedMesh *dm);
#endif
+/* utilities */
+void GPU_select_index_set(int index);
+void GPU_select_index_get(int index, int *r_col);
+int GPU_select_to_index(unsigned int col);
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 74fe1762bcb..d435935302f 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -263,6 +263,7 @@ void GPU_material_vertex_attributes(GPUMaterial *material,
bool GPU_material_do_color_management(GPUMaterial *mat);
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
+bool GPU_material_use_world_space_shading(GPUMaterial *mat);
/* BRDF Shading */
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index 088dac6f6cc..a2b89239344 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -51,8 +51,6 @@
/* State */
-static const bool USE_GLSL = false;
-
static struct {
GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
@@ -269,6 +267,24 @@ const GLubyte stipple_hexagon[128] = {
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
/* ********************************************* */
+/* GLSL State */
+
+static bool USE_GLSL = false;
+
+/**
+ * \note this isn't part of the basic shader API,
+ * only set from the command line once on startup.
+ */
+void GPU_basic_shader_use_glsl_set(bool enabled)
+{
+ USE_GLSL = enabled;
+}
+
+bool GPU_basic_shader_use_glsl_get(void)
+{
+ return USE_GLSL;
+}
+
/* Init / exit */
void GPU_basic_shaders_init(void)
@@ -308,6 +324,9 @@ static int detect_options()
if (glIsEnabled(GL_TEXTURE_2D))
options |= GPU_SHADER_TEXTURE_2D;
+ if (glIsEnabled(GL_TEXTURE_RECTANGLE))
+ options |= GPU_SHADER_TEXTURE_RECT;
+ GPU_SHADER_TEXTURE_RECT
if (glIsEnabled(GL_COLOR_MATERIAL))
options |= GPU_SHADER_USE_COLOR;
@@ -347,14 +366,18 @@ static GPUShader *gpu_basic_shader(int options)
strcat(defines, "#define USE_COLOR\n");
if (options & GPU_SHADER_TWO_SIDED)
strcat(defines, "#define USE_TWO_SIDED\n");
- if (options & GPU_SHADER_TEXTURE_2D)
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT))
strcat(defines, "#define USE_TEXTURE\n");
+ if (options & GPU_SHADER_TEXTURE_RECT)
+ strcat(defines, "#define USE_TEXTURE_RECTANGLE\n");
if (options & GPU_SHADER_STIPPLE)
strcat(defines, "#define USE_STIPPLE\n");
if (options & GPU_SHADER_LINE) {
strcat(defines, "#define DRAW_LINE\n");
geom_glsl = datatoc_gpu_shader_basic_geom_glsl;
}
+ if (options & GPU_SHADER_FLAT_NORMAL)
+ strcat(defines, "#define USE_FLAT_NORMAL\n");
if (options & GPU_SHADER_SOLID_LIGHTING)
strcat(defines, "#define USE_SOLID_LIGHTING\n");
else if (options & GPU_SHADER_LIGHTING)
@@ -369,7 +392,7 @@ static GPUShader *gpu_basic_shader(int options)
if (shader) {
/* set texture map to first texture unit */
- if (options & GPU_SHADER_TEXTURE_2D) {
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) {
GPU_shader_bind(shader);
glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
GPU_shader_unbind();
@@ -399,6 +422,23 @@ void GPU_basic_shader_bind(int options)
{
if (USE_GLSL) {
if (options) {
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
+
+ /* texture options need to be set for basic shader too */
+ if (options & GPU_SHADER_TEXTURE_2D) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_2D) {
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ glEnable(GL_TEXTURE_RECTANGLE);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
GPUShader *shader = gpu_basic_shader(options);
if (shader) {
@@ -411,7 +451,7 @@ void GPU_basic_shader_bind(int options)
}
}
else {
- int bound_options = GPU_MATERIAL_STATE.bound_options;
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
if (options & GPU_SHADER_LIGHTING) {
glEnable(GL_LIGHTING);
@@ -438,28 +478,59 @@ void GPU_basic_shader_bind(int options)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
}
else if (bound_options & GPU_SHADER_TEXTURE_2D) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if ((options & GPU_SHADER_TEXTURE_RECT) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
glDisable(GL_TEXTURE_2D);
}
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
+ glEnable(GL_TEXTURE_RECTANGLE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ if ((options & GPU_SHADER_TEXTURE_2D) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) {
glEnable(GL_LINE_STIPPLE);
}
else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) {
glDisable(GL_LINE_STIPPLE);
}
- else {
- if (options & GPU_SHADER_STIPPLE)
- glEnable(GL_POLYGON_STIPPLE);
- else if (bound_options & GPU_SHADER_STIPPLE)
- glDisable(GL_POLYGON_STIPPLE);
+
+ if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) {
+ glEnable(GL_POLYGON_STIPPLE);
+ }
+ else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) {
+ glDisable(GL_POLYGON_STIPPLE);
}
+ if (options & GPU_SHADER_FLAT_NORMAL) {
+ glShadeModel(GL_FLAT);
+ }
+ else if (bound_options & GPU_SHADER_FLAT_NORMAL) {
+ glShadeModel(GL_SMOOTH);
+ }
}
GPU_MATERIAL_STATE.bound_options = options;
}
+void GPU_basic_shader_bind_enable(int options)
+{
+ GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options | options);
+}
+
+void GPU_basic_shader_bind_disable(int options)
+{
+ GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options & ~options);
+}
+
int GPU_basic_shader_bound_options(void)
{
/* ideally this should disappear, anything that uses this is making fragile
@@ -469,8 +540,9 @@ int GPU_basic_shader_bound_options(void)
/* Material Colors */
-void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha)
+void GPU_basic_shader_colors(
+ const float diffuse[3], const float specular[3],
+ int shininess, float alpha)
{
float gl_diffuse[4], gl_specular[4];
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 2c6f204d9d0..36d297fb9fe 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -53,8 +53,6 @@
#include "BKE_mesh.h"
#include "BKE_pbvh.h"
-#include "DNA_userdef_types.h"
-
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_basic_shader.h"
@@ -1845,15 +1843,15 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
if (buffers->vert_buf) {
char *base = NULL;
char *index_base = NULL;
- int bound_options = 0;
+ /* weak inspection of bound options, should not be necessary ideally */
+ const int bound_options_old = GPU_basic_shader_bound_options();
+ int bound_options_new = 0;
glEnableClientState(GL_VERTEX_ARRAY);
if (!wireframe) {
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- /* weak inspection of bound options, should not be necessary ideally */
- bound_options = GPU_basic_shader_bound_options();
- GPU_basic_shader_bind(bound_options | GPU_SHADER_USE_COLOR);
+ bound_options_new |= GPU_SHADER_USE_COLOR;
}
GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY);
@@ -1865,10 +1863,18 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX);
}
- if (wireframe)
+ if (wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- else
- glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT);
+ }
+ else {
+ if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) {
+ bound_options_new |= GPU_SHADER_FLAT_NORMAL;
+ }
+ }
+
+ if (bound_options_new & ~bound_options_old) {
+ GPU_basic_shader_bind(bound_options_old | bound_options_new);
+ }
if (buffers->tot_quad) {
const char *offset = base;
@@ -1942,7 +1948,10 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
if (!wireframe) {
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
- GPU_basic_shader_bind(bound_options);
+ }
+
+ if (bound_options_new & ~bound_options_old) {
+ GPU_basic_shader_bind(bound_options_old);
}
}
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index fae60031589..c8920039a19 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -98,8 +98,10 @@ typedef struct GPUFunction {
} GPUFunction;
/* Indices match the GPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
- NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"};
+static const char *GPU_DATATYPE_STR[17] = {
+ "", "float", "vec2", "vec3", "vec4",
+ NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4",
+};
/* GLSL code parsing for finding function definitions.
* These are stored in a hash for lookup when creating a material. */
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index d015f7c715a..d1c54ea9865 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -34,17 +34,12 @@
#include "BLI_sys_types.h"
#include "BLI_rect.h"
#include "BLI_math.h"
-#include "BLI_listbase.h"
-#include "BLI_linklist.h"
#include "BKE_colortools.h"
#include "BKE_scene.h"
#include "DNA_vec_types.h"
-#include "DNA_view3d_types.h"
#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_camera_types.h"
#include "DNA_gpu_types.h"
#include "IMB_colormanagement.h"
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 655b56aea90..ec274ebef54 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -39,7 +39,6 @@
#include <string.h>
#include "GPU_glew.h"
-#include "GPU_debug.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
@@ -70,10 +69,11 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
-#include "BKE_object.h"
#include "BKE_scene.h"
-#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h"
+#ifdef WITH_GAMEENGINE
+# include "BKE_object.h"
+#endif
#include "GPU_basic_shader.h"
#include "GPU_buffers.h"
@@ -87,9 +87,12 @@
#include "PIL_time.h"
-#include "smoke_API.h"
+#ifdef WITH_SMOKE
+# include "smoke_API.h"
+#endif
#ifdef WITH_OPENSUBDIV
+# include "BKE_subsurf.h"
# include "BKE_editmesh.h"
# include "gpu_codegen.h"
@@ -568,7 +571,9 @@ static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
}
}
-int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap)
+int GPU_verify_image(
+ Image *ima, ImageUser *iuser,
+ int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap)
{
unsigned int *bind = NULL;
int tpx = 0, tpy = 0;
@@ -850,8 +855,9 @@ static void gpu_del_cube_map(void **cube_map)
}
/* Image *ima can be NULL */
-void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- int textarget, bool mipmap, bool use_high_bit_depth, Image *ima, bool is_envmap)
+void GPU_create_gl_tex(
+ unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
+ int textarget, bool mipmap, bool use_high_bit_depth, Image *ima, bool is_envmap)
{
ImBuf *ibuf = NULL;
@@ -2102,8 +2108,9 @@ int GPU_object_material_bind(int nr, void *attribs)
}
else {
/* or do fixed function opengl material */
- GPU_basic_shader_colors(GMS.matbuf[nr].diff,
- GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
+ GPU_basic_shader_colors(
+ GMS.matbuf[nr].diff,
+ GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
if (GMS.two_sided_lighting)
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
@@ -2399,8 +2406,6 @@ void GPU_state_init(void)
/* scaling matrices */
glEnable(GL_NORMALIZE);
- glShadeModel(GL_FLAT);
-
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
@@ -2479,3 +2484,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm)
}
}
#endif
+
+
+/** \name Framebuffer color depth, for selection codes
+ * \{ */
+
+#ifdef __APPLE__
+
+/* apple seems to round colors to below and up on some configs */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x070707;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x030303;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x010101;
+ break;
+ }
+
+ return i;
+}
+
+#else
+
+/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
+ i |= 0x3F3F3F;
+ break;
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x0F0F0F;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x070707;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x030303;
+ break;
+ }
+
+ return i;
+}
+
+#endif
+
+
+void GPU_select_index_set(int index)
+{
+ const int col = index_to_framebuffer(index);
+ glColor3ub(( (col) & 0xFF),
+ (((col) >> 8) & 0xFF),
+ (((col) >> 16) & 0xFF));
+}
+
+void GPU_select_index_get(int index, int *r_col)
+{
+ const int col = index_to_framebuffer(index);
+ char *c_col = (char *)r_col;
+ c_col[0] = (col & 0xFF); /* red */
+ c_col[1] = ((col >> 8) & 0xFF); /* green */
+ c_col[2] = ((col >> 16) & 0xFF); /* blue */
+ c_col[3] = 0xFF; /* alpha */
+}
+
+
+#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6))
+#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4))
+#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3))
+#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2))
+#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF)
+
+int GPU_select_to_index(unsigned int col)
+{
+ if (col == 0) {
+ return 0;
+ }
+
+ switch (GPU_color_depth()) {
+ case 8: return INDEX_FROM_BUF_8(col);
+ case 12: return INDEX_FROM_BUF_12(col);
+ case 15:
+ case 16: return INDEX_FROM_BUF_15_16(col);
+ case 24: return INDEX_FROM_BUF_24(col);
+ default: return INDEX_FROM_BUF_18(col);
+ }
+}
+
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
+{
+#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
+ for (i = size; i--; col++) { \
+ if ((c = *col)) { \
+ *col = INDEX_FROM_BUF_BITS(c); \
+ } \
+ } ((void)0)
+
+ if (size > 0) {
+ unsigned int i, c;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
+ break;
+ case 12:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
+ break;
+ case 15:
+ case 16:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
+ break;
+ case 24:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
+ break;
+ default:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
+ break;
+ }
+ }
+
+#undef INDEX_BUF_ARRAY
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 567925a130e..acec8a13520 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -32,9 +32,6 @@
* with checks for drivers and GPU support.
*/
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
@@ -42,7 +39,6 @@
#include "BKE_global.h"
#include "GPU_basic_shader.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_texture.h"
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 3736d3f673f..d0a4d8a0ac0 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -30,7 +30,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
#include "BKE_global.h"
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 8fed6a9ee80..c72c83b6b07 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -29,11 +29,8 @@
* \ingroup gpu
*/
-#include "BKE_DerivedMesh.h"
-
#include "BLI_sys_types.h"
#include "GPU_init_exit.h" /* interface */
-#include "GPU_buffers.h"
#include "BKE_global.h"
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 29e31676ab8..77ad923faaa 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -31,7 +31,6 @@
* Manages materials, lights and textures.
*/
-
#include <math.h>
#include <string.h>
@@ -50,7 +49,6 @@
#include "BKE_anim.h"
#include "BKE_colortools.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_image.h"
@@ -73,7 +71,9 @@
#include "gpu_codegen.h"
-#include <string.h>
+#ifdef WITH_OPENSUBDIV
+# include "BKE_DerivedMesh.h"
+#endif
/* Structs */
@@ -870,6 +870,11 @@ bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
return BKE_scene_use_new_shading_nodes(mat->scene);
}
+bool GPU_material_use_world_space_shading(GPUMaterial *mat)
+{
+ return BKE_scene_use_world_space_shading(mat->scene);
+}
+
static GPUNodeLink *lamp_get_lightcolor(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink *lv)
{
// if (lamp->use_realistic_lighting) {
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 6371259d32c..16cebf36a8e 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -27,7 +27,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index 6b6679b60df..01a335af048 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -3,6 +3,7 @@
*
* USE_COLOR: use glColor for diffuse colors
* USE_TEXTURE: use texture for diffuse colors
+ * USE_TEXTURE_RECTANGLE: use GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D
* USE_SCENE_LIGHTING: use lights (up to 8)
* USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
* USE_TWO_SIDED: flip normal towards viewer
@@ -27,8 +28,11 @@
#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if defined(USE_FLAT_NORMAL)
+varying vec3 eyespace_vert_pos;
+#else
varying vec3 varying_normal;
-
+#endif
#ifndef USE_SOLID_LIGHTING
varying vec3 varying_position;
#endif
@@ -39,8 +43,16 @@ varying vec4 varying_vertex_color;
#endif
#ifdef USE_TEXTURE
+#ifdef USE_TEXTURE_RECTANGLE
+#define sampler2D_default sampler2DRect
+#define texture2D_default texture2DRect
+#else
+#define sampler2D_default sampler2D
+#define texture2D_default texture2D
+#endif
+
varying vec2 varying_texture_coord;
-uniform sampler2D texture_map;
+uniform sampler2D_default texture_map;
#endif
#ifdef USE_STIPPLE
@@ -137,7 +149,11 @@ void main()
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
/* compute normal */
+#if defined(USE_FLAT_NORMAL)
+ vec3 N = normalize(cross(dFdx(eyespace_vert_pos), dFdy(eyespace_vert_pos)));
+#else
vec3 N = normalize(varying_normal);
+#endif
#ifdef USE_TWO_SIDED
if (!gl_FrontFacing)
@@ -229,12 +245,12 @@ void main()
float alpha;
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+ vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
alpha = texture_color.a * varying_vertex_color.a;
#elif defined(USE_TEXTURE)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+ vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
L_diffuse *= texture_color.rgb;
alpha = texture_color.a;
@@ -259,9 +275,9 @@ void main()
/* no lighting */
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord) * varying_vertex_color;
#elif defined(USE_TEXTURE)
- gl_FragColor = texture2D(texture_map, varying_texture_coord);
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord);
#elif defined(USE_COLOR)
gl_FragColor = varying_vertex_color;
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index cef28ea3026..42fbdadf1d1 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -1,6 +1,10 @@
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if defined(USE_FLAT_NORMAL)
+varying vec3 eyespace_vert_pos;
+#else
varying vec3 varying_normal;
+#endif
#ifndef USE_SOLID_LIGHTING
varying vec3 varying_position;
@@ -28,7 +32,13 @@ void main()
vec4 co = gl_ModelViewMatrix * gl_Vertex;
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if !defined(USE_FLAT_NORMAL)
varying_normal = normalize(gl_NormalMatrix * gl_Normal);
+#endif
+#if defined(USE_FLAT_NORMAL)
+ /* transform vertex into eyespace */
+ eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
+#endif
#ifndef USE_SOLID_LIGHTING
varying_position = co.xyz;
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 9a6537b4f09..db0068d2f3d 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,6 +14,9 @@ varying vec3 varnormal;
varying float gl_ClipDistance[6];
#endif
+
+/* Color, keep in sync with: gpu_shader_vertex_world.glsl */
+
float srgb_to_linearrgb(float c)
{
if (c < 0.04045)
@@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var)
}
}
+/* end color code */
+
+
void main()
{
#ifndef USE_OPENSUBDIV
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
index fe02a883765..d45a4b316a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
@@ -2,6 +2,9 @@
varying vec3 varposition;
varying vec3 varnormal;
+
+/* Color, keep in sync with: gpu_shader_vertex.glsl */
+
float srgb_to_linearrgb(float c)
{
if (c < 0.04045)
@@ -64,6 +67,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var)
}
}
+/* end color code */
+
+
void main()
{
/* position does not need to be transformed, we already have it */
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 5ec0a87890c..6fb1bccf491 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -296,10 +296,11 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement,
row[index] = swap_uint(pixel, logImage->isMSB);
if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
- if (verbose) printf("DPX/Cineon: Error while writing file.\n"); {
- MEM_freeN(row);
- return 1;
+ if (verbose) {
+ printf("DPX/Cineon: Error while writing file.\n");
}
+ MEM_freeN(row);
+ return 1;
}
}
MEM_freeN(row);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index fdadb783815..89e796fb7ee 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -77,7 +77,7 @@ extern "C"
{
// The following prevents a linking error in debug mode for MSVC using the libs in CVS
-#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__)
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && _MSC_VER < 1900
_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
@@ -127,7 +127,7 @@ class Mem_IStream : public Imf::IStream
{
public:
- Mem_IStream (unsigned char *exrbuf, size_t exrsize) :
+ Mem_IStream(unsigned char *exrbuf, size_t exrsize) :
IStream("dummy"), _exrpos(0), _exrsize(exrsize)
{
_exrbuf = exrbuf;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 95d061bcb75..3629332a4ac 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -46,6 +46,8 @@
#include "BLO_readfile.h"
+#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_thumbs.h"
@@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
char thumb_path[FILE_MAX];
char thumb_name[40];
char uri[URI_MAX];
- char path_buff[FILE_MAX];
+ char path_buff[FILE_MAX_LIBEXTRA];
const char *file_path;
const char *path;
BLI_stat_t st;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 0bf3c350263..b0812a81ee1 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -142,7 +142,6 @@ typedef struct ID {
*/
typedef struct Library {
ID id;
- ID *idblock;
struct FileData *filedata;
char name[1024]; /* path name used for reading, can be relative and edited in the outliner */
@@ -155,6 +154,9 @@ typedef struct Library {
struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */
struct PackedFile *packedfile;
+
+ int temp_index;
+ int _pad;
} Library;
enum eIconSizes {
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 4c1283452ff..6bd7b3a4999 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -537,8 +537,9 @@ typedef enum eFCurve_Extend {
/* curve coloring modes */
typedef enum eFCurve_Coloring {
FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */
- FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */
- FCURVE_COLOR_CUSTOM /* custom color */
+ FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */
+ FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */
+ FCURVE_COLOR_CUSTOM = 2, /* custom color */
} eFCurve_Coloring;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 68741578f27..52e40cbc098 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -85,8 +85,8 @@ typedef struct Camera {
char sensor_fit;
char pad[7];
- /* Stereo settings */
- struct CameraStereoSettings stereo;
+ /* Stereo settings */
+ struct CameraStereoSettings stereo;
} Camera;
/* **************** CAMERA ********************* */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 8f711c1b23b..61169e4b1b1 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -230,7 +230,7 @@ typedef struct Curve {
/* font part */
short lines;
- char spacemode, pad1;
+ char spacemode, align_y;
float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight;
float xof, yof;
float linewidth;
@@ -322,11 +322,19 @@ enum {
/* Curve.spacemode */
enum {
- CU_LEFT = 0,
- CU_MIDDLE = 1,
- CU_RIGHT = 2,
- CU_JUSTIFY = 3,
- CU_FLUSH = 4,
+ CU_ALIGN_X_LEFT = 0,
+ CU_ALIGN_X_MIDDLE = 1,
+ CU_ALIGN_X_RIGHT = 2,
+ CU_ALIGN_X_JUSTIFY = 3,
+ CU_ALIGN_X_FLUSH = 4,
+};
+
+/* Curve.align_y */
+enum {
+ CU_ALIGN_Y_TOP_BASELINE = 0,
+ CU_ALIGN_Y_TOP = 1,
+ CU_ALIGN_Y_CENTER = 2,
+ CU_ALIGN_Y_BOTTOM = 3,
};
/* Nurb.flag */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 457db70cd28..a58e995f1c6 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1518,7 +1518,9 @@ typedef struct NormalEditModifierData {
short mix_mode;
char pad[2];
float mix_factor;
+ float mix_limit;
float offset[3];
+ float pad_f1;
} NormalEditModifierData;
/* NormalEditModifierData.mode */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 354314ddc65..3a76c7f1063 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -913,7 +913,8 @@ typedef struct NodeSunBeams {
#define SHD_GLOSSY_BECKMANN 0
#define SHD_GLOSSY_SHARP 1
#define SHD_GLOSSY_GGX 2
-#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_MULTI_GGX 4
/* vector transform */
#define SHD_VECT_TRANSFORM_TYPE_VECTOR 0
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1bf044ffecb..79af1813a8f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1639,6 +1639,7 @@ typedef struct Scene {
#define R_SIMPLIFY 0x1000000
#define R_EDGE_FRS 0x2000000 /* R_EDGE reserved for Freestyle */
#define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */
+#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
/* seq_flag */
#define R_SEQ_GL_PREV 1
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
index 28204ebeb88..cb7a371c7c5 100644
--- a/source/blender/makesdna/DNA_sdna_types.h
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -67,7 +67,7 @@ typedef struct SDNA {
#
typedef struct BHead {
int code, len;
- void *old;
+ const void *old;
int SDNAnr, nr;
} BHead;
#
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 46b7d717991..9c177cdddd1 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -875,8 +875,6 @@ typedef struct SpaceImage {
struct Image *image;
struct ImageUser iuser;
- struct CurveMapping *cumap DNA_DEPRECATED; /* was switched to scene's color management settings */
-
struct Scopes scopes; /* histogram waveform and vectorscope */
struct Histogram sample_line_hist; /* sample line histogram */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 52487edfd2b..0bb6e866bf4 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -56,8 +56,14 @@ add_executable(makesdna ${SRC} ${SRC_DNA_INC})
# Output dna.c
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c
- COMMAND "$<TARGET_FILE:makesdna>" ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/
+ OUTPUT
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ COMMAND
+ "$<TARGET_FILE:makesdna>"
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ ${CMAKE_SOURCE_DIR}/source/blender/makesdna/
DEPENDS makesdna
)
@@ -78,7 +84,11 @@ set(SRC
${SRC_DNA_INC}
)
-set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dna.c PROPERTIES GENERATED TRUE)
+set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ PROPERTIES GENERATED TRUE
+)
blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}")
@@ -94,10 +104,11 @@ set(INC_SYS
)
set(SRC
- ../../blenlib/intern/BLI_mempool.c
- ../../blenlib/intern/listbase.c
../../blenlib/intern/BLI_ghash.c
+ ../../blenlib/intern/BLI_mempool.c
+ ../../blenlib/intern/endian_switch.c
../../blenlib/intern/hash_mm2a.c
+ ../../blenlib/intern/listbase.c
)
blender_add_lib(bf_dna_blenlib "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 4f19e819625..99ab29fbdcc 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -43,6 +43,7 @@
#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
#include "BLI_utildefines.h"
+#include "BLI_endian_switch.h"
#ifdef WITH_DNA_GHASH
# include "BLI_ghash.h"
@@ -1126,7 +1127,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
*/
int a, mul, elemcount, elen, elena, firststructtypenr;
const short *spo, *spc;
- char *cpo, *cur, cval;
+ char *cur;
const char *type, *name;
if (oldSDNAnr == -1) return;
@@ -1148,9 +1149,9 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
/* test: is type a struct? */
if (spc[0] >= firststructtypenr && !ispointer(name)) {
- /* struct field type */
+ /* struct field type */
/* where does the old data start (is there one?) */
- cpo = find_elem(oldsdna, type, name, spo, data, NULL);
+ char *cpo = find_elem(oldsdna, type, name, spo, data, NULL);
if (cpo) {
oldSDNAnr = DNA_struct_find_nr(oldsdna, type);
@@ -1167,18 +1168,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
/* non-struct field type */
if (ispointer(name)) {
if (oldsdna->pointerlen == 8) {
-
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval;
- cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval;
- cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval;
- cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval;
-
- cpo += 8;
- }
-
+ BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
}
}
else {
@@ -1191,14 +1181,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
}
if (skip == false) {
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0];
- cpo[0] = cpo[1];
- cpo[1] = cval;
- cpo += 2;
- }
+ BLI_endian_switch_int16_array((int16_t *)cur, DNA_elem_array_size(name));
}
}
else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) {
@@ -1206,29 +1189,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
* but turns out we only used for runtime vars and
* only once for a struct type thats no longer used. */
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0];
- cpo[0] = cpo[3];
- cpo[3] = cval;
- cval = cpo[1];
- cpo[1] = cpo[2];
- cpo[2] = cval;
- cpo += 4;
- }
+ BLI_endian_switch_int32_array((int32_t *)cur, DNA_elem_array_size(name));
}
else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) {
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval;
- cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval;
- cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval;
- cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval;
-
- cpo += 8;
- }
+ BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
}
}
}
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index fc94a8d9ff4..b78299316e1 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -968,7 +968,7 @@ void printStructLengths(void)
}
-static int make_structDNA(const char *baseDirectory, FILE *file)
+static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offsets)
{
int len, i;
const short *sp;
@@ -1159,6 +1159,19 @@ static int make_structDNA(const char *baseDirectory, FILE *file)
/* end end padding test */
}
+ /* write a simple enum with all structs offsets,
+ * should only be accessed via SDNA_TYPE_FROM_STRUCT macro */
+ {
+ fprintf(file_offsets, "#define SDNA_TYPE_FROM_STRUCT(id) _SDNA_TYPE_##id\n");
+ fprintf(file_offsets, "enum {\n");
+ for (i = 0; i < nr_structs; i++) {
+ const short *structpoin = structs[i];
+ const int structtype = structpoin[0];
+ fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", types[structtype], i);
+ }
+ fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs);
+ fprintf(file_offsets, "};\n");
+ }
MEM_freeN(namedata);
MEM_freeN(typedata);
@@ -1190,43 +1203,53 @@ static void make_bad_file(const char *file, int line)
int main(int argc, char **argv)
{
- FILE *file;
int return_status = 0;
- if (argc != 2 && argc != 3) {
- printf("Usage: %s outfile.c [base directory]\n", argv[0]);
+ if (argc != 3 && argc != 4) {
+ printf("Usage: %s dna.c dna_struct_offsets.h [base directory]\n", argv[0]);
return_status = 1;
}
else {
- file = fopen(argv[1], "w");
- if (!file) {
+ FILE *file_dna = fopen(argv[1], "w");
+ FILE *file_dna_offsets = fopen(argv[2], "w");
+ if (!file_dna) {
printf("Unable to open file: %s\n", argv[1]);
return_status = 1;
}
+ else if (!file_dna_offsets) {
+ printf("Unable to open file: %s\n", argv[2]);
+ return_status = 1;
+ }
else {
const char *baseDirectory;
- if (argc == 3) {
- baseDirectory = argv[2];
+ if (argc == 4) {
+ baseDirectory = argv[3];
}
else {
baseDirectory = BASE_HEADER;
}
- fprintf(file, "const unsigned char DNAstr[] = {\n");
- if (make_structDNA(baseDirectory, file)) {
+ fprintf(file_dna, "const unsigned char DNAstr[] = {\n");
+ if (make_structDNA(baseDirectory, file_dna, file_dna_offsets)) {
/* error */
- fclose(file);
+ fclose(file_dna);
+ file_dna = NULL;
make_bad_file(argv[1], __LINE__);
return_status = 1;
}
else {
- fprintf(file, "};\n");
- fprintf(file, "const int DNAlen = sizeof(DNAstr);\n");
-
- fclose(file);
+ fprintf(file_dna, "};\n");
+ fprintf(file_dna, "const int DNAlen = sizeof(DNAstr);\n");
}
}
+
+ if (file_dna) {
+ fclose(file_dna);
+ }
+ if (file_dna_offsets) {
+ fclose(file_dna_offsets);
+ }
}
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d8bea93bcbc..1d5f46a1814 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -285,6 +285,11 @@ typedef struct CollectionPointerLink {
PointerRNA ptr;
} CollectionPointerLink;
+/* Copy of ListBase for RNA... */
+typedef struct CollectionListBase {
+ struct CollectionPointerLink *first, *last;
+} CollectionListBase;
+
typedef enum RawPropertyType {
PROP_RAW_UNSET = -1,
PROP_RAW_INT, // XXX - abused for types that are not set, eg. MFace.verts, needs fixing.
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 535847cfc78..f9a46409aea 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -227,6 +227,10 @@ static const char *rna_safe_id(const char *id)
return "operator_value";
else if (STREQ(id, "new"))
return "create";
+ else if (STREQ(id, "co_return")) {
+ /* MSVC2015, C++ uses for coroutines */
+ return "coord_return";
+ }
return id;
}
@@ -466,7 +470,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm)
}
case PROP_COLLECTION:
{
- return "ListBase";
+ return "CollectionListBase";
}
default:
return "<error, no type specified>";
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 63ea836e3de..dc6d30854a6 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -87,10 +87,13 @@ EnumPropertyItem rna_enum_id_type_items[] = {
#include "DNA_anim_types.h"
+#include "BLI_listbase.h"
+
#include "BKE_font.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
#include "BKE_depsgraph.h"
@@ -333,6 +336,14 @@ static void rna_ID_user_clear(ID *id)
id->us = 0; /* don't save */
}
+static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
+{
+ if (GS(id->name) == GS(new_id->name)) {
+ /* For now, do not allow remapping data in linked data from here... */
+ BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ }
+}
+
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
@@ -342,7 +353,7 @@ static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
static void rna_ID_animation_data_free(ID *id, Main *bmain)
{
- BKE_animdata_free(id);
+ BKE_animdata_free(id, true);
DAG_relations_tag_update(bmain);
}
@@ -977,6 +988,12 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
+ func = RNA_def_function(srna, "user_remap", "rna_ID_user_remap");
+ RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use");
+ RNA_def_property_flag(parm, PROP_NEVER_NULL);
+
func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index c49a6197a4e..0eaeabccd99 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -4678,7 +4678,7 @@ static void rna_path_array_multi_string_from_flat_index(
}
/**
- * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
* \param index: The *flattened* index to use when \a ``index_dim > 0``,
* this is expanded when used with multi-dimensional arrays.
*/
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 678b0ac8f1f..492430fbda6 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index cb7a40a9238..fb4ff6f4856 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -952,23 +952,37 @@ static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *srna)
static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
{
PropertyRNA *prop;
-
+
static EnumPropertyItem prop_align_items[] = {
- {CU_LEFT, "LEFT", 0, "Left", "Align text to the left"},
- {CU_MIDDLE, "CENTER", 0, "Center", "Center text"},
- {CU_RIGHT, "RIGHT", 0, "Right", "Align text to the right"},
- {CU_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"},
- {CU_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"},
+ {CU_ALIGN_X_LEFT, "LEFT", 0, "Left", "Align text to the left"},
+ {CU_ALIGN_X_MIDDLE, "CENTER", 0, "Center", "Center text"},
+ {CU_ALIGN_X_RIGHT, "RIGHT", 0, "Right", "Align text to the right"},
+ {CU_ALIGN_X_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"},
+ {CU_ALIGN_X_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"},
{0, NULL, 0, NULL, NULL}
};
-
+
+ static EnumPropertyItem prop_align_y_items[] = {
+ {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", 0, "Top Base-Line", "Align to top but use the base-line of the text"},
+ {CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"},
+ {CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"},
+ {CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* Enums */
- prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacemode");
RNA_def_property_enum_items(prop, prop_align_items);
- RNA_def_property_ui_text(prop, "Text Align", "Text align from the object center");
+ RNA_def_property_ui_text(prop, "Text Horizontal Align", "Text horizontal align from the object center");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-
+
+ prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "align_y");
+ RNA_def_property_enum_items(prop, prop_align_y_items);
+ RNA_def_property_ui_text(prop, "Text Vertical Align", "Text vertical align from the object center");
+ RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fsize");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 1487dfa074e..3043c5452c0 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -1844,6 +1844,8 @@ static void rna_def_fcurve(BlenderRNA *brna)
"Cycle through the rainbow, trying to give each curve a unique color"},
{FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB",
"Use axis colors for transform and color properties, and auto-rainbow for the rest"},
+ {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB",
+ "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"},
{FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined",
"Use custom hand-picked color for F-Curve"},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 4b7ce640a56..c0a0bc0b55a 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -58,9 +58,11 @@
#include "BKE_armature.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_icons.h"
+#include "BKE_idcode.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
@@ -113,30 +115,38 @@
# include "BPY_extern.h"
#endif
+
+static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink)
+{
+ ID *id = id_ptr->data;
+ if (do_unlink) {
+ BKE_libblock_delete(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else if (ID_REAL_USERS(id) <= 0) {
+ BKE_libblock_free(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)",
+ BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id));
+ }
+}
+
+
static Camera *rna_Main_cameras_new(Main *bmain, const char *name)
{
ID *id = BKE_camera_add(bmain, name);
id_us_min(id);
return (Camera *)id;
}
-static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr)
-{
- Camera *camera = camera_ptr->data;
- if (ID_REAL_USERS(camera) <= 0) {
- BKE_libblock_free(bmain, camera);
- RNA_POINTER_INVALIDATE(camera_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d",
- camera->id.name + 2, ID_REAL_USERS(camera));
- }
-}
static Scene *rna_Main_scenes_new(Main *bmain, const char *name)
{
return BKE_scene_add(bmain, name);
}
-static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr)
+static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink)
{
/* don't call BKE_libblock_free(...) directly */
Scene *scene = scene_ptr->data;
@@ -145,23 +155,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
if ((scene_new = scene->id.prev) ||
(scene_new = scene->id.next))
{
- bScreen *sc = CTX_wm_screen(C);
- if (sc->scene == scene) {
+ if (do_unlink) {
+ bScreen *sc = CTX_wm_screen(C);
+ if (sc->scene == scene) {
#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
+ BPy_BEGIN_ALLOW_THREADS;
#endif
- ED_screen_set_scene(C, sc, scene_new);
+ ED_screen_set_scene(C, sc, scene_new);
#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
+ BPy_END_ALLOW_THREADS;
#endif
+ }
}
-
- BKE_scene_unlink(bmain, scene, scene_new);
- RNA_POINTER_INVALIDATE(scene_ptr);
+ rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink);
}
else {
BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2);
@@ -222,38 +232,12 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
return ob;
}
-static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr)
-{
- Object *object = object_ptr->data;
- if (ID_REAL_USERS(object) <= 0) {
- BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */
- BKE_libblock_free(bmain, object);
- RNA_POINTER_INVALIDATE(object_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d",
- object->id.name + 2, ID_REAL_USERS(object));
- }
-}
-
static Material *rna_Main_materials_new(Main *bmain, const char *name)
{
ID *id = (ID *)BKE_material_add(bmain, name);
id_us_min(id);
return (Material *)id;
}
-static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr)
-{
- Material *material = material_ptr->data;
- if (ID_REAL_USERS(material) <= 0) {
- BKE_libblock_free(bmain, material);
- RNA_POINTER_INVALIDATE(material_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d",
- material->id.name + 2, ID_REAL_USERS(material));
- }
-}
static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -271,18 +255,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in
else
return NULL;
}
-static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr)
-{
- bNodeTree *ntree = ntree_ptr->data;
- if (ID_REAL_USERS(ntree) <= 0) {
- BKE_libblock_free(bmain, ntree);
- RNA_POINTER_INVALIDATE(ntree_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d",
- ntree->id.name + 2, ID_REAL_USERS(ntree));
- }
-}
static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
{
@@ -312,19 +284,6 @@ Mesh *rna_Main_meshes_new_from_object(
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
-static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)
-{
- Mesh *mesh = mesh_ptr->data;
- if (ID_REAL_USERS(mesh) <= 0) {
- BKE_libblock_free(bmain, mesh);
- RNA_POINTER_INVALIDATE(mesh_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d",
- mesh->id.name + 2, ID_REAL_USERS(mesh));
- }
-}
-
static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
{
Lamp *lamp = BKE_lamp_add(bmain, name);
@@ -332,18 +291,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
id_us_min(&lamp->id);
return lamp;
}
-static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr)
-{
- Lamp *lamp = lamp_ptr->data;
- if (ID_REAL_USERS(lamp) <= 0) {
- BKE_libblock_free(bmain, lamp);
- RNA_POINTER_INVALIDATE(lamp_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d",
- lamp->id.name + 2, ID_REAL_USERS(lamp));
- }
-}
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
@@ -372,18 +319,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char
id_us_min((ID *)ima);
return ima;
}
-static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr)
-{
- Image *image = image_ptr->data;
- if (ID_REAL_USERS(image) <= 0) {
- BKE_libblock_free(bmain, image);
- RNA_POINTER_INVALIDATE(image_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d",
- image->id.name + 2, ID_REAL_USERS(image));
- }
-}
static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
{
@@ -391,18 +326,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
id_us_min(&lt->id);
return lt;
}
-static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr)
-{
- Lattice *lt = lt_ptr->data;
- if (ID_REAL_USERS(lt) <= 0) {
- BKE_libblock_free(bmain, lt);
- RNA_POINTER_INVALIDATE(lt_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d",
- lt->id.name + 2, ID_REAL_USERS(lt));
- }
-}
static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
{
@@ -410,18 +333,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
id_us_min(&cu->id);
return cu;
}
-static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr)
-{
- Curve *cu = cu_ptr->data;
- if (ID_REAL_USERS(cu) <= 0) {
- BKE_libblock_free(bmain, cu);
- RNA_POINTER_INVALIDATE(cu_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d",
- cu->id.name + 2, ID_REAL_USERS(cu));
- }
-}
static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
{
@@ -429,18 +340,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
id_us_min(&mb->id);
return mb;
}
-static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr)
-{
- MetaBall *mb = mb_ptr->data;
- if (ID_REAL_USERS(mb) <= 0) {
- BKE_libblock_free(bmain, mb);
- RNA_POINTER_INVALIDATE(mb_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d",
- mb->id.name + 2, ID_REAL_USERS(mb));
- }
-}
static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -462,18 +361,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *
return font;
}
-static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr)
-{
- VFont *vfont = vfont_ptr->data;
- if (ID_REAL_USERS(vfont) <= 0) {
- BKE_libblock_free(bmain, vfont);
- RNA_POINTER_INVALIDATE(vfont_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d",
- vfont->id.name + 2, ID_REAL_USERS(vfont));
- }
-}
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
@@ -482,18 +369,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
id_us_min(&tex->id);
return tex;
}
-static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr)
-{
- Tex *tex = tex_ptr->data;
- if (ID_REAL_USERS(tex) <= 0) {
- BKE_libblock_free(bmain, tex);
- RNA_POINTER_INVALIDATE(tex_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d",
- tex->id.name + 2, ID_REAL_USERS(tex));
- }
-}
static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
{
@@ -502,50 +377,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
return brush;
}
-static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr)
-{
- Brush *brush = brush_ptr->data;
- if (ID_REAL_USERS(brush) <= 0) {
- BKE_brush_unlink(bmain, brush);
- BKE_libblock_free(bmain, brush);
- RNA_POINTER_INVALIDATE(brush_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d",
- brush->id.name + 2, ID_REAL_USERS(brush));
- }
-}
-
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
World *world = add_world(bmain, name);
id_us_min(&world->id);
return world;
}
-static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr)
-{
- Group *world = world_ptr->data;
- if (ID_REAL_USERS(world) <= 0) {
- BKE_libblock_free(bmain, world);
- RNA_POINTER_INVALIDATE(world_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d",
- world->id.name + 2, ID_REAL_USERS(world));
- }
-}
static Group *rna_Main_groups_new(Main *bmain, const char *name)
{
return BKE_group_add(bmain, name);
}
-static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr)
-{
- Group *group = group_ptr->data;
- BKE_group_unlink(bmain, group);
- BKE_libblock_free(bmain, group);
- RNA_POINTER_INVALIDATE(group_ptr);
-}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
{
@@ -553,18 +395,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
id_us_min(&speaker->id);
return speaker;
}
-static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr)
-{
- Speaker *speaker = speaker_ptr->data;
- if (ID_REAL_USERS(speaker) <= 0) {
- BKE_libblock_free(bmain, speaker);
- RNA_POINTER_INVALIDATE(speaker_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d",
- speaker->id.name + 2, ID_REAL_USERS(speaker));
- }
-}
static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing)
{
@@ -580,30 +410,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi
id_us_min(&sound->id);
return sound;
}
-static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr)
-{
- Speaker *sound = sound_ptr->data;
- if (ID_REAL_USERS(sound) <= 0) {
- BKE_libblock_free(bmain, sound);
- RNA_POINTER_INVALIDATE(sound_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d",
- sound->id.name + 2, ID_REAL_USERS(sound));
- }
-}
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
return BKE_text_add(bmain, name);
}
-static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr)
-{
- Text *text = text_ptr->data;
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
- RNA_POINTER_INVALIDATE(text_ptr);
-}
static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal)
{
@@ -625,18 +436,6 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name)
id_us_min(&arm->id);
return arm;
}
-static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr)
-{
- bArmature *arm = arm_ptr->data;
- if (ID_REAL_USERS(arm) <= 0) {
- BKE_libblock_free(bmain, arm);
- RNA_POINTER_INVALIDATE(arm_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d",
- arm->id.name + 2, ID_REAL_USERS(arm));
- }
-}
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
@@ -644,18 +443,6 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name)
id_fake_user_clear(&act->id);
return act;
}
-static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr)
-{
- bAction *act = act_ptr->data;
- if (ID_REAL_USERS(act) <= 0) {
- BKE_libblock_free(bmain, act);
- RNA_POINTER_INVALIDATE(act_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d",
- act->id.name + 2, ID_REAL_USERS(act));
- }
-}
static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
{
@@ -663,18 +450,6 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
id_us_min(&part->id);
return part;
}
-static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerRNA *part_ptr)
-{
- ParticleSettings *part = part_ptr->data;
- if (ID_REAL_USERS(part) <= 0) {
- BKE_libblock_free(bmain, part);
- RNA_POINTER_INVALIDATE(part_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Particle settings '%s' must have zero users to be removed, found %d",
- part->id.name + 2, ID_REAL_USERS(part));
- }
-}
static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
{
@@ -682,18 +457,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
id_us_min(&palette->id);
return (Palette *)palette;
}
-static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr)
-{
- Palette *palette = palette_ptr->data;
- if (ID_REAL_USERS(palette) <= 0) {
- BKE_libblock_free(bmain, palette);
- RNA_POINTER_INVALIDATE(palette_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d",
- palette->id.name + 2, ID_REAL_USERS(palette));
- }
-}
static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -716,14 +479,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
return clip;
}
-static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr)
-{
- MovieClip *clip = clip_ptr->data;
- BKE_movieclip_unlink(bmain, clip);
- BKE_libblock_free(bmain, clip);
- RNA_POINTER_INVALIDATE(clip_ptr);
-}
-
static Mask *rna_Main_mask_new(Main *bmain, const char *name)
{
Mask *mask;
@@ -733,27 +488,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name)
return mask;
}
-static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr)
-{
- Mask *mask = mask_ptr->data;
- BKE_mask_free(bmain, mask);
- BKE_libblock_free(bmain, mask);
- RNA_POINTER_INVALIDATE(mask_ptr);
-}
-
-static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr)
-{
- bGPdata *gpd = gpd_ptr->data;
- if (ID_REAL_USERS(gpd) <= 0) {
- BKE_gpencil_free(gpd);
- BKE_libblock_free(bmain, gpd);
- RNA_POINTER_INVALIDATE(gpd_ptr);
- }
- else
- BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d",
- gpd->id.name + 2, ID_REAL_USERS(gpd));
-}
-
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
@@ -761,17 +495,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
-{
- if (ID_REAL_USERS(linestyle) <= 0)
- BKE_libblock_free(bmain, linestyle);
- else
- BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d",
- linestyle->id.name + 2, ID_REAL_USERS(linestyle));
-
- /* XXX python now has invalid pointer? */
-}
-
/* tag and is_updated functions, all the same */
#define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \
@@ -854,12 +577,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a camera from the current blendfile");
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this camera before deleting it "
+ "(WARNING: will also delete objects instancing that camera data)");
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -896,6 +622,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -930,12 +657,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_objects_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a object from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -966,12 +694,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_materials_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1009,12 +738,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile");
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1067,12 +797,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this mesh before deleting it "
+ "(WARNING: will also delete objects instancing that mesh data)");
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1104,12 +837,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile");
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lamp before deleting it "
+ "(WARNING: will also delete objects instancing that lamp data)");
func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1219,12 +955,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_images_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove an image from the current blendfile");
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1255,12 +992,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile");
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lattice before deleting it "
+ "(WARNING: will also delete objects instancing that lattice data)");
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1292,12 +1032,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_curves_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a curve from the current blendfile");
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this curve before deleting it "
+ "(WARNING: will also delete objects instancing that curve data)");
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1327,12 +1070,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile");
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this metaball before deleting it "
+ "(WARNING: will also delete objects instancing that metaball data)");
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1364,12 +1110,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a font from the current blendfile");
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1401,12 +1148,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_textures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a texture from the current blendfile");
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1437,12 +1185,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a brush from the current blendfile");
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1473,12 +1222,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a world from the current blendfile");
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1509,11 +1259,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_groups_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a group from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1544,12 +1296,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile");
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this speaker before deleting it "
+ "(WARNING: will also delete objects instancing that speaker data)");
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1580,11 +1335,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_texts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a text from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
@@ -1628,12 +1385,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1664,12 +1422,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a armature from the current blendfile");
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this armature before deleting it "
+ "(WARNING: will also delete objects instancing that armature data)");
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1699,12 +1460,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_actions_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a action from the current blendfile");
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1734,12 +1496,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_particles_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile");
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them");
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1769,12 +1532,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a palette from the current blendfile");
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1808,12 +1572,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile");
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1836,11 +1601,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile.");
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1886,11 +1653,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* remove func */
- func = RNA_def_function(srna, "remove", "rna_Main_masks_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a masks from the current blendfile.");
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1921,11 +1690,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile");
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 0c4b3ba485d..a7c9f29e7d3 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1826,6 +1826,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hook Center", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "parentinv");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target");
+ RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -4602,6 +4608,11 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
"How much of generated normals to mix with exiting ones", 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_float(srna, "mix_limit", 1.0f, 0.0f, DEG2RADF(180.0f), "Max Angle",
+ "Maximum angle between old and new normals", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index bf7e4634c2f..7f2cd1e6080 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3193,12 +3193,14 @@ static EnumPropertyItem node_glossy_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem node_anisotropic_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3207,6 +3209,14 @@ static EnumPropertyItem node_glass_items[] = {
{SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem node_refraction_items[] = {
+ {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4159,6 +4169,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_refraction(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_refraction_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_anisotropic(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 55b3fd905dc..b31cdc38775 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2480,6 +2480,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_array(prop, 3);
+ /* only for the transform-panel and conflicts with animating scale */
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 3f401a29945..a52473b95f2 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -341,7 +341,7 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f);
}
- if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem))
+ if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem, particlesystem->renderdata != NULL))
return;
if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT)
@@ -586,7 +586,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc
psys_render_set(object, particlesystem, mat, mat, 1, 1, 0.f);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(scene, object, particlesystem);
+ particle_system_update(scene, object, particlesystem, true);
}
else {
ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem);
@@ -596,7 +596,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc
}
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(scene, object, particlesystem);
+ particle_system_update(scene, object, particlesystem, false);
}
}
@@ -2635,35 +2635,35 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "normfac"); /*optional if prop names are the same */
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "object_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "obfac");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "factor_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "randfac"); /*optional if prop names are the same */
RNA_def_property_range(prop, 0.0f, 200.0f);
RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Random", "Give the starting speed a random variation");
+ RNA_def_property_ui_text(prop, "Random", "Give the starting velocity a random variation");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "particle_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "partfac");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "tangent_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "tanfac");
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_range(prop, -100, 100, 1, 2);
- RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "tangent_phase", PROP_FLOAT, PROP_NONE);
@@ -2677,7 +2677,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, -10.0f, 10.0f);
RNA_def_property_ui_text(prop, "Reactor",
"Let the vector away from the target particle's location give the particle "
- "a starting speed");
+ "a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "object_align_factor", PROP_FLOAT, PROP_VELOCITY);
@@ -2686,7 +2686,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -100, 100, 1, 3);
RNA_def_property_ui_text(prop, "Object Aligned",
- "Let the emitter object orientation give the particle a starting speed");
+ "Let the emitter object orientation give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 06823a26c77..1f34d8f23d4 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -898,7 +898,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL);
RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle",
- "Use treat custom start handle position as a relative value");
+ "Treat custom start handle position as a relative value");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -914,7 +914,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL);
RNA_def_property_ui_text(prop, "Relative B-Bone End Handle",
- "Use treat custom end handle position as a relative value");
+ "Treat custom end handle position as a relative value");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 4d1a3d9400e..6882aea5d71 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5577,6 +5577,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS);
RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
+ prop = RNA_def_property(srna, "use_world_space_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", R_USE_WS_SHADING);
+ RNA_def_property_ui_text(prop, "World Space Shading", "Use world space interpretation of lighting data for node materials");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index c3c66625c84..1d3537dc9a0 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -196,7 +196,7 @@ static void rna_Scene_collada_export(
int use_ngons,
int use_object_instantiation,
- int use_blender_profile,
+ int use_blender_profile,
int sort_by_name,
int export_transformation_type,
int open_sim)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index fd90c16405c..4dd5cd2624c 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1831,7 +1831,7 @@ static void rna_FileBrowser_FSMenu_active_range(
static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr))
{
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr)
@@ -2577,14 +2577,16 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "near");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "far");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 5a1607aa7c7..d8dcbf1afd0 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -94,6 +94,13 @@ EnumPropertyItem rna_enum_navigation_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME)
+static EnumPropertyItem rna_enum_language_default_items[] = {
+ {0, "DEFAULT", 0, "Default (Default)", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
#ifdef RNA_RUNTIME
#include "DNA_object_types.h"
@@ -642,7 +649,11 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi
static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
- return BLT_lang_RNA_enum_properties();
+ EnumPropertyItem *items = BLT_lang_RNA_enum_properties();
+ if (items == NULL) {
+ items = rna_enum_language_default_items;
+ }
+ return items;
}
#endif
@@ -3971,11 +3982,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample (requires restart)"},
{0, NULL, 0, NULL, NULL}
};
-
- static EnumPropertyItem language_items[] = {
- {0, "DEFAULT", 0, "Default (Default)", ""},
- {0, NULL, 0, NULL, NULL}
- };
#ifdef WITH_CYCLES
static EnumPropertyItem compute_device_items[] = {
@@ -4058,7 +4064,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
/* Language Selection */
prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, language_items);
+ RNA_def_property_enum_items(prop, rna_enum_language_default_items);
#ifdef WITH_INTERNATIONAL
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf");
#endif
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 0d11414c878..026d2e209a3 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -469,13 +469,15 @@ EnumPropertyItem rna_enum_wm_report_items[] = {
static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->id.data;
- IDProperty *properties = (IDProperty *)ptr->data;
- wmOperator *op;
- if (wm)
- for (op = wm->operators.first; op; op = op->next)
- if (op->properties == properties)
+ if (wm) {
+ IDProperty *properties = (IDProperty *)ptr->data;
+ for (wmOperator *op = wm->operators.last; op; op = op->prev) {
+ if (op->properties == properties) {
return op;
+ }
+ }
+ }
return NULL;
}
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..44515bfdf35 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
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 355dd6d6677..2cfa746ab3c 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -110,7 +110,7 @@ static void generate_vert_coordinates(
/* Note this modifies nos_new in-place. */
static void mix_normals(
const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
- const short mix_mode,
+ const float mix_limit, const short mix_mode,
const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops)
{
/* Mix with org normals... */
@@ -143,7 +143,9 @@ static void mix_normals(
case MOD_NORMALEDIT_MIX_COPY:
break;
}
- interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac);
+
+ interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new,
+ (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
}
MEM_SAFE_FREE(facs);
@@ -156,6 +158,7 @@ static bool polygons_check_flip(
MPoly *mpoly, float (*polynors)[3], const int num_polys)
{
MPoly *mp;
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
int i;
bool flipped = false;
@@ -174,7 +177,7 @@ static bool polygons_check_flip(
/* If average of new loop normals is opposed to polygon normal, flip polygon. */
if (dot_v3v3(polynors[i], norsum) < 0.0f) {
- BKE_mesh_polygon_flip(mp, mloop, ldata);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true);
negate_v3(polynors[i]);
flipped = true;
}
@@ -186,7 +189,7 @@ static bool polygons_check_flip(
static void normalEditModifier_do_radial(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
@@ -265,11 +268,13 @@ static void normalEditModifier_do_radial(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* We need to recompute vertex normals! */
+ dm->calcNormals(dm);
}
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
@@ -283,7 +288,7 @@ static void normalEditModifier_do_radial(
static void normalEditModifier_do_directional(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
@@ -342,7 +347,7 @@ static void normalEditModifier_do_directional(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
@@ -384,7 +389,8 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(smd->mix_factor == 1.0f) &&
- (smd->defgrp_name[0] == '\0'));
+ (smd->defgrp_name[0] == '\0') &&
+ (smd->mix_limit == M_PI));
int defgrp_index;
MDeformVert *dvert;
@@ -439,13 +445,13 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
@@ -464,6 +470,7 @@ static void initData(ModifierData *md)
smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
smd->mix_factor = 1.0f;
+ smd->mix_limit = M_PI;
}
static void copyData(ModifierData *md, ModifierData *target)
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 4791e41d433..d8cccca415c 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -101,7 +101,7 @@ static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
int UNUSED(numVerts),
- ModifierApplyFlag UNUSED(flag))
+ ModifierApplyFlag flag)
{
DerivedMesh *dm = derivedData;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
@@ -114,7 +114,7 @@ static void deformVerts(ModifierData *md, Object *ob,
else
return;
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, (flag & MOD_APPLY_RENDER) != 0))
return;
if (dm == NULL) {
@@ -186,7 +186,7 @@ static void deformVerts(ModifierData *md, Object *ob,
if (!(ob->transflag & OB_NO_PSYS_UPDATE)) {
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(md->scene, ob, psys);
+ particle_system_update(md->scene, ob, psys, (flag & MOD_APPLY_RENDER) != 0);
psmd->flag |= eParticleSystemFlag_psys_updated;
}
}
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_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/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 9e1a0c926fa..171d5313c1d 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 29b1e5bc5c7..8523b7275bf 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -57,6 +57,8 @@
#include "RE_shader_ext.h"
+#include "NOD_common.h"
+
#include "node_common.h"
#include "node_exec.h"
#include "node_util.h"
@@ -199,6 +201,12 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
+static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
+ bNode *node_from,
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket);
+
/* Find an output node of the shader tree.
*
* NOTE: it will only return output which is NOT in the group, which isn't how
@@ -277,32 +285,139 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
return displacement->link != NULL;
}
+static bool ntree_shader_relink_node_normal(bNodeTree *ntree,
+ bNode *node,
+ bNode *node_from,
+ bNodeSocket *socket_from)
+{
+ bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
+ /* TODO(sergey): Can we do something smarter here than just a name-based
+ * matching?
+ */
+ if (sock == NULL) {
+ /* There's no Normal input, nothing to link. */
+ return false;
+ }
+ if (sock->link != NULL) {
+ /* Something is linked to the normal input already. can't
+ * use other input for that.
+ */
+ return false;
+ }
+ /* Create connection between specified node and the normal input. */
+ nodeAddLink(ntree, node_from, socket_from, node, sock);
+ return true;
+}
+
+static void ntree_shader_link_builtin_group_normal(
+ bNodeTree *ntree,
+ bNode *group_node,
+ bNode *node_from,
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket)
+{
+ bNodeTree *group_ntree = (bNodeTree *)group_node->id;
+ /* Create input socket to plug displacement connection to. */
+ bNodeSocket *group_normal_socket =
+ ntreeAddSocketInterface(group_ntree,
+ SOCK_IN,
+ "NodeSocketVector",
+ "Normal");
+ /* Need to update tree so all node instances nodes gets proper sockets. */
+ bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
+ node_group_verify(ntree, group_node, &group_ntree->id);
+ node_group_input_verify(group_ntree, group_input_node, &group_ntree->id);
+ ntreeUpdateTree(G.main, group_ntree);
+ /* Assumes sockets are always added at the end. */
+ bNodeSocket *group_node_normal_socket = group_node->inputs.last;
+ if (displacement_node == group_node) {
+ /* If displacement is coming from this node group we need to perform
+ * some internal re-linking in order to avoid cycles.
+ */
+ bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT);
+ BLI_assert(group_output_node != NULL);
+ bNodeSocket *group_output_node_displacement_socket =
+ nodeFindSocket(group_output_node,
+ SOCK_IN,
+ displacement_socket->identifier);
+ bNodeLink *group_displacement_link = group_output_node_displacement_socket->link;
+ if (group_displacement_link == NULL) {
+ /* Displacement output is not connected to anything, can just stop
+ * right away.
+ */
+ return;
+ }
+ /* This code is similar to ntree_shader_relink_displacement() */
+ bNode *group_displacement_node = group_displacement_link->fromnode;
+ bNodeSocket *group_displacement_socket = group_displacement_link->fromsock;
+ /* Create and link bump node.
+ * Can't re-use bump node from parent tree because it'll cause cycle.
+ */
+ bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP);
+ bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
+ bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
+ BLI_assert(bump_input_socket != NULL);
+ BLI_assert(bump_output_socket != NULL);
+ nodeAddLink(group_ntree,
+ group_displacement_node, group_displacement_socket,
+ bump_node, bump_input_socket);
+ /* Relink normals inside of the instanced tree. */
+ ntree_shader_link_builtin_normal(group_ntree,
+ bump_node,
+ bump_output_socket,
+ group_displacement_node,
+ group_displacement_socket);
+ ntreeUpdateTree(G.main, group_ntree);
+ }
+ else {
+ /* Connect group node normal input. */
+ nodeAddLink(ntree,
+ node_from, socket_from,
+ group_node, group_node_normal_socket);
+ BLI_assert(group_input_node != NULL);
+ bNodeSocket *group_input_node_normal_socket =
+ nodeFindSocket(group_input_node,
+ SOCK_OUT,
+ group_normal_socket->identifier);
+ BLI_assert(group_input_node_normal_socket != NULL);
+ /* Relink normals inside of the instanced tree. */
+ ntree_shader_link_builtin_normal(group_ntree,
+ group_input_node,
+ group_input_node_normal_socket,
+ displacement_node,
+ displacement_socket);
+ ntreeUpdateTree(G.main, group_ntree);
+ }
+}
+
/* Use specified node and socket as an input for unconnected normal sockets. */
static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
- bNodeSocket *socket_from)
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket)
{
for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
if (node == node_from) {
/* Don't connect node itself! */
continue;
}
- bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
- /* TODO(sergey): Can we do something smarter here than just a name-based
- * matching?
- */
- if (sock == NULL) {
- /* There's no Normal input, nothing to link. */
+ if (node->type == NODE_GROUP && node->id) {
+ /* Special re-linking for group nodes. */
+ ntree_shader_link_builtin_group_normal(ntree,
+ node,
+ node_from,
+ socket_from,
+ displacement_node,
+ displacement_socket);
continue;
}
- if (sock->link != NULL) {
- /* Something is linked to the normal input already. can't
- * use other input for that.
- */
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ /* Group inputs and outputs needs nothing special. */
continue;
}
- /* Create connection between specified node and the normal input. */
- nodeAddLink(ntree, node_from, socket_from, node, sock);
+ ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
}
}
@@ -346,7 +461,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree,
displacement_node, displacement_socket,
bump_node, bump_input_socket);
/* Connect all free-standing Normal inputs. */
- ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
+ ntree_shader_link_builtin_normal(ntree,
+ bump_node,
+ bump_output_socket,
+ displacement_node,
+ displacement_socket);
/* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new
* bump node.
*/
@@ -369,7 +488,7 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili
ntreeExecGPUNodes(exec, mat, 1, compatibility);
ntreeShaderEndExecTree(exec);
- ntreeFreeTree_ex(localtree, false);
+ ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
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_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
index cd52c4e2547..b289d66efc3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -78,6 +78,10 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b
copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv);
copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno);
+ if (shi->use_world_space_shading) {
+ negate_v3(out[GEOM_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec);
+ }
if (shi->totcol) {
/* find vertex color layer by name */
ShadeInputCol *scol = &shi->col[0];
@@ -132,9 +136,14 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname);
GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname);
- return GPU_stack_link(mat, "geom", in, out,
+ bool ret = GPU_stack_link(mat, "geom", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link);
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link);
+ }
+ return ret;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index 6ff5cb0e8c4..d3483c8c826 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -54,6 +54,8 @@ static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, b
shi->nodes = 1; /* temp hack to prevent trashadow recursion */
out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec);
shi->nodes = 0;
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[1]->vec);
}
}
}
@@ -66,7 +68,10 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy);
- return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ if (GPU_material_use_world_space_shading(mat))
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link);
+ return ret;
}
return false;
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index fa13f6191ad..8b21b1ff33b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -114,6 +114,10 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
+ if (shi->use_world_space_shading) {
+ negate_v3(shi->vn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn);
+ }
normalize_v3(shi->vn);
}
else
@@ -181,7 +185,11 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
}
copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
-
+
+ if (shi->use_world_space_shading) {
+ negate_v3(out[MAT_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec);
+ }
/* Extended material options */
if (node->type == SH_NODE_MATERIAL_EXT) {
/* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
@@ -255,6 +263,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (hasinput[MAT_IN_NORMAL]) {
GPUNodeLink *tmp;
shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
+ GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
+ }
GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
}
@@ -299,6 +311,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (node->custom1 & SH_NODE_MAT_NEG)
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
out[MAT_OUT_NORMAL].link = shi.vn;
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link);
+ GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link);
+ }
if (node->type == SH_NODE_MATERIAL_EXT) {
out[MAT_OUT_DIFFUSE].link = shr.diff;
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 85e2c77662d..48d1688c386 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -89,20 +89,34 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
for (int j = 0; j < 3; j++)
out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec);
+ }
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ }
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
}
+ if (shi->use_world_space_shading) {
+ negate_v3(out[0]->vec);
+ }
normalize_v3(out[0]->vec);
}
}
@@ -129,10 +143,13 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
negnorm = GPU_builtin(GPU_VIEW_NORMAL);
GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
- if (GPU_material_use_new_shading_nodes(mat)) {
+ if (GPU_material_use_world_space_shading(mat)) {
- /* **************** CYCLES ******************** */
+ /* ******* CYCLES or BLENDER INTERNAL with world space shading flag ******* */
+ const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
+ if (nm->space == SHD_NORMAL_MAP_BLENDER_OBJECT || nm->space == SHD_NORMAL_MAP_BLENDER_WORLD || !GPU_material_use_new_shading_nodes(mat))
+ color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
@@ -143,28 +160,22 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
return true;
case SHD_NORMAL_MAP_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
- break;
case SHD_NORMAL_MAP_BLENDER_OBJECT:
GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_WORLD:
- GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
- break;
case SHD_NORMAL_MAP_BLENDER_WORLD:
GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
break;
}
- } else {
+ }
+ else {
- /* *********** BLENDER INTERNAL *************** */
+ /* ************** BLENDER INTERNAL without world space shading flag ******* */
GPU_link(mat, "color_to_normal", realnorm, &realnorm);
GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 832d516b839..2ad8ee0547f 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1586,8 +1586,11 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
-
- if (length > restlen || no_compress) {
+
+ /* This code computes not only the force, but also its derivative.
+ Zero derivative effectively disables the spring for the implicit solver.
+ Thus length > restlen makes cloth unconstrained at the start of simulation. */
+ if ((length >= restlen && length > 0) || no_compress) {
float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
stretch_force = stiffness * (length - restlen);
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 a0722af522b..fe4360d1e3b 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1803,6 +1803,82 @@ static PyObject *bpy_bmface_calc_perimeter(BPy_BMFace *self)
}
+PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_doc,
+".. method:: calc_tangent_edge()\n"
+"\n"
+" Return face tangent based on longest edge.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+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"
+"\n"
+" - Tris: Use the edge pair with the most similar lengths.\n"
+" - Quads: Use the longest edge pair.\n"
+" - NGons: Use the two longest disconnected edges.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge_pair(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge_pair(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_diagonal_doc,
+".. method:: calc_tangent_edge_diagonal()\n"
+"\n"
+" Return face tangent based on the edge farthest from any vertex.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge_diagonal(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+PyDoc_STRVAR(bpy_bmface_calc_tangent_vert_diagonal_doc,
+".. method:: calc_tangent_vert_diagonal()\n"
+"\n"
+" Return face tangent based on the two most distent vertices.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_vert_diagonal(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_vert_diagonal(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
PyDoc_STRVAR(bpy_bmface_calc_center_mean_doc,
".. method:: calc_center_median()\n"
"\n"
@@ -2702,6 +2778,10 @@ static struct PyMethodDef bpy_bmface_methods[] = {
{"calc_area", (PyCFunction)bpy_bmface_calc_area, METH_NOARGS, bpy_bmface_calc_area_doc},
{"calc_perimeter", (PyCFunction)bpy_bmface_calc_perimeter, METH_NOARGS, bpy_bmface_calc_perimeter_doc},
+ {"calc_tangent_edge", (PyCFunction)bpy_bmface_calc_tangent_edge, METH_NOARGS, bpy_bmface_calc_tangent_edge_doc},
+ {"calc_tangent_edge_pair", (PyCFunction)bpy_bmface_calc_tangent_edge_pair, METH_NOARGS, bpy_bmface_calc_tangent_edge_pair_doc},
+ {"calc_tangent_edge_diagonal", (PyCFunction)bpy_bmface_calc_tangent_edge_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_edge_diagonal_doc},
+ {"calc_tangent_vert_diagonal", (PyCFunction)bpy_bmface_calc_tangent_vert_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_vert_diagonal_doc},
{"calc_center_median", (PyCFunction)bpy_bmface_calc_center_mean, METH_NOARGS, bpy_bmface_calc_center_mean_doc},
{"calc_center_median_weighted", (PyCFunction)bpy_bmface_calc_center_mean_weighted, METH_NOARGS, bpy_bmface_calc_center_mean_weighted_doc},
{"calc_center_bounds", (PyCFunction)bpy_bmface_calc_center_bounds, METH_NOARGS, bpy_bmface_calc_center_bounds_doc},
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/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index d6c57f4c302..eaa96e6243c 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
if ((reports->flag & RPT_FREE) == 0) {
MEM_freeN(reports);
}
+ else {
+ /* The WM is now responsible for running the modal operator,
+ * show reports in the info window. */
+ reports->flag &= ~RPT_OP_HOLD;
+ }
}
WM_operator_properties_free(&ptr);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 49b806347d6..1c6471c2cca 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -5220,7 +5220,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
}
case PROP_COLLECTION:
{
- ListBase *lb = (ListBase *)data;
+ CollectionListBase *lb = (CollectionListBase *)data;
CollectionPointerLink *link;
ret = PyList_New(0);
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 8b6dfb88b73..73867de6b2e 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -172,6 +172,7 @@ typedef struct ShadeInput {
/* from initialize, part or renderlayer */
bool do_preview; /* for nodes, in previewrender */
bool do_manage; /* color management flag */
+ bool use_world_space_shading;
short thread, sample; /* sample: ShadeSample array index */
short nodes; /* indicate node shading, temp hack to prevent recursion */
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
index 3607e66a237..1935e4ef59c 100644
--- a/source/blender/render/intern/include/rayintersection.h
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -38,6 +38,8 @@
extern "C" {
#endif
+#include "BLI_math_geom.h"
+
struct RayObject;
/* Ray Hints */
@@ -101,6 +103,9 @@ typedef struct Isect {
#ifdef RE_RAYCOUNTER
RayCounter *raycounter;
#endif
+
+ /* Precalculated coefficients for watertight intersection check. */
+ struct IsectRayPrecalc isect_precalc;
} Isect;
/* ray types */
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index de6b9139363..f511042749e 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,80 +138,29 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
+MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
- int quad;
-
- quad = RE_rayface_isQuad(face);
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
-
- copy_v3_v3(r, dir);
-
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = v;
- *lambda = l;
- return 1;
- }
- }
+ float uv[2], l;
+
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 1;
}
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = -(1.0f + v + u);
- *lambda = l;
- return 2;
- }
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 2;
}
}
}
@@ -223,62 +172,23 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, fl
MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
- int quad;
-
- quad = RE_rayface_isQuad(face);
+ float r[3];
+ struct IsectRayPrecalc isect_precalc;
+ float uv[2], l;
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
negate_v3_v3(r, dir); /* note, different than above function */
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 1;
- }
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ return 1;
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 2;
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ return 2;
}
}
@@ -317,7 +227,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i
RE_RC_COUNT(is->raycounter->faces.test);
dist = is->dist;
- ok = isec_tri_quad(is->start, is->dir, face, uv, &dist);
+ ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
if (ok) {
@@ -389,6 +299,9 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec)
{
int i;
+ /* Pre-calculate orientation for watertight intersection checks. */
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
RE_RC_COUNT(isec->raycounter->raycast.test);
/* setup vars used on raycast */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index b6ee88de290..907974e20dc 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1330,7 +1330,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
part=psys->part;
pars=psys->particles;
- if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys))
+ if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering))
return 0;
if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
@@ -2816,7 +2816,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag || timeoffset==0) {
+ if (dl->bevel_split || timeoffset == 0) {
const int startvlak= obr->totvlak;
for (a=0; a<dl->parts; a++) {
@@ -2856,10 +2856,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag) {
- for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++)
- if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F)))
- split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U);
+ if (dl->bevel_split) {
+ for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
+ if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
+ split_v_renderfaces(
+ obr, startvlak, startvert, dl->parts, dl->nr, a,
+ /* intentionally swap (v, u) --> (u, v) */
+ dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
+ }
+ }
}
/* vertex normals */
@@ -3167,9 +3172,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
@@ -4697,7 +4701,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
if (ob->particlesystem.first) {
psysindex= 1;
for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index c88e3b36e27..7af63051dfe 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -66,6 +66,7 @@
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -2177,12 +2178,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 +2268,8 @@ static void free_all_freestyle_renders(void)
if (freestyle_render) {
freestyle_scene = freestyle_render->scene;
RE_FreeRender(freestyle_render);
- BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL);
+ BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false, false);
+ BKE_libblock_free(re1->freestyle_bmain, freestyle_scene);
}
}
BLI_freelistN(&re1->freestyle_renders);
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 59aaad661c9..e4da4302efe 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -211,7 +211,7 @@ static void pointdensity_cache_psys(Scene *scene,
CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
}
- if (!psys_check_enabled(ob, psys)) {
+ if (!psys_check_enabled(ob, psys, use_render_params)) {
psys_render_restore(ob, psys);
return;
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 8f61f4159e6..530ebc084be 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -3806,6 +3806,7 @@ void RE_sample_material_free(Material *mat)
MTex *mtex= mat->mtex[tex_nr];
if (mtex->tex) {
+ /* don't update user counts as we are freeing a duplicate */
BKE_texture_free(mtex->tex);
MEM_freeN(mtex->tex);
mtex->tex = NULL;
@@ -3814,7 +3815,7 @@ void RE_sample_material_free(Material *mat)
}
/* don't update user counts as we are freeing a duplicate */
- BKE_material_free_ex(mat, false);
+ BKE_material_free(mat);
MEM_freeN(mat);
}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 6e01921a6a7..20602314526 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -1339,6 +1339,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in
shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0;
shi->do_manage = BKE_scene_check_color_management_enabled(R.scene);
+ shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene);
shi->lay = rl->lay;
shi->layflag = rl->layflag;
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 388837af67a..7a247d9791b 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -191,7 +191,7 @@ void WM_ndof_deadzone_set(float deadzone);
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
void WM_main_remove_notifier_reference(const void *reference);
-void WM_main_remove_editor_id_reference(const struct ID *id);
+void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
/* reports */
void WM_report_banner_show(void);
@@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2);
void wmOrtho2_region_pixelspace(const struct ARegion *ar);
void wmOrtho2_pixelspace(const float x, const float y);
- /* utilities */
-void WM_framebuffer_index_set(int index);
-void WM_framebuffer_index_get(int index, int *r_col);
-int WM_framebuffer_to_index(unsigned int col);
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size);
-
/* threaded Jobs Manager */
enum {
WM_JOB_PRIORITY = (1 << 0),
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 8f15d94f538..962ed3c040d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -437,8 +437,6 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
float halfx, halfy, ratiox, ratioy;
- glEnable(triple->target);
-
/* wmOrtho for the screen has this same offset */
ratiox = sizex;
ratioy = sizey;
@@ -453,6 +451,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
halfy /= triple->y;
}
+ GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+
glBindTexture(triple->target, triple->bind);
glColor4f(1.0f, 1.0f, 1.0f, alpha);
@@ -471,7 +471,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
glEnd();
glBindTexture(triple->target, 0);
- glDisable(triple->target);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 4f9d48450f6..4515ae92f66 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -241,7 +241,7 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-void WM_main_remove_editor_id_reference(const ID *id)
+void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
{
Main *bmain = G.main;
bScreen *sc;
@@ -253,7 +253,7 @@ void WM_main_remove_editor_id_reference(const ID *id)
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
- ED_spacedata_id_unref(sl, id);
+ ED_spacedata_id_remap(sa, sl, old_id, new_id);
}
}
}
@@ -793,7 +793,10 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
wm_operator_finished(C, op, repeat);
}
else if (repeat == 0) {
- WM_operator_free(op);
+ /* warning: modal from exec is bad practice, but avoid crashing. */
+ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
+ WM_operator_free(op);
+ }
}
return retval | OPERATOR_HANDLED;
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 2e4a4b63b7a..12ad8f91064 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -61,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -211,7 +212,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
}
static void wm_link_do(
- WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d,
+ const bool use_placeholders, const bool force_indirect)
{
Main *mainl;
BlendHandle *bh;
@@ -258,9 +260,11 @@ static void wm_link_do(
continue;
}
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ new_id = BLO_library_link_named_part_ex(
+ mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect);
+
if (new_id) {
- /* If the link is sucessful, clear item's libs 'todo' flags.
+ /* If the link is successful, clear item's libs 'todo' flags.
* This avoids trying to link same item with other libraries to come. */
BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
item->new_id = new_id;
@@ -401,7 +405,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
/* BKE_main_lock(bmain); */
- wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+ wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false);
/* BKE_main_unlock(bmain); */
@@ -518,3 +522,393 @@ void WM_OT_append(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All",
"Localize all appended data, including those indirectly linked from other libraries");
}
+
+/** \name Reload/relocate libraries.
+ *
+ * \{ */
+
+static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Library *lib;
+ char lib_name[MAX_NAME];
+
+ RNA_string_get(op->ptr, "library", lib_name);
+ lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name);
+
+ if (lib) {
+ if (lib->parent) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot relocate indirectly linked library '%s'", lib->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ RNA_string_set(op->ptr, "filepath", lib->filepath);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+/* Note that IDs listed in lapp_data items *must* have been removed from bmain by caller. */
+static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int lba_idx;
+
+ LinkNode *itemlink;
+ int item_idx;
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We do not want any instanciation here! */
+ wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload);
+
+ BKE_main_lock(bmain);
+
+ /* We add back old id to bmain.
+ * We need to do this in a first, separated loop, otherwise some of those may not be handled by
+ * ID remapping, which means they would still reference old data to be deleted... */
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+
+ BLI_assert(old_id);
+ BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
+ }
+
+ /* Note that in reload case, we also want to replace indirect usages. */
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+ ID *new_id = item->new_id;
+
+ BLI_assert(old_id);
+ if (do_reload) {
+ /* Since we asked for placeholders in case of missing IDs, we expect to always get a valid one. */
+ BLI_assert(new_id);
+ }
+ if (new_id) {
+#ifdef PRINT_DEBUG
+ printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us);
+#endif
+ BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
+
+ if (old_id->flag & LIB_FAKEUSER) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+#ifdef PRINT_DEBUG
+ printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us);
+#endif
+
+ /* In some cases, new_id might become direct link, remove parent of library in this case. */
+ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
+ if (do_reload) {
+ BLI_assert(0); /* Should not happen in 'pure' reload case... */
+ }
+ new_id->lib->parent = NULL;
+ }
+ }
+
+ if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
+ /* Note that this *should* not happen - but better be safe than sorry in this area, at least until we are
+ * 100% sure this cannot ever happen.
+ * Also, we can safely assume names were unique so far, so just replacing '.' by '~' should work,
+ * but this does not totally rules out the possibility of name collision. */
+ size_t len = strlen(old_id->name);
+ size_t dot_pos;
+ bool has_num = false;
+
+ for (dot_pos = len; dot_pos--;) {
+ char c = old_id->name[dot_pos];
+ if (c == '.') {
+ break;
+ }
+ else if (c < '0' || c > '9') {
+ has_num = false;
+ break;
+ }
+ has_num = true;
+ }
+
+ if (has_num) {
+ old_id->name[dot_pos] = '~';
+ }
+ else {
+ len = MIN2(len, MAX_ID_NAME - 7);
+ BLI_strncpy(&old_id->name[len], "~000", 7);
+ }
+
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id);
+
+ BKE_reportf(reports, RPT_WARNING,
+ "Lib Reload: Replacing all references to old datablock '%s' by reloaded one failed, "
+ "old one (%d remaining users) had to be kept and was renamed to '%s'",
+ new_id->name, old_id->us, old_id->name);
+ }
+ }
+
+ BKE_main_unlock(bmain);
+
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+
+ if (old_id->us == 0) {
+ BKE_libblock_free(bmain, old_id);
+ }
+ }
+
+ /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable (shape keys e.g.),
+ * so we need another loop here to clear old ones if possible. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id, *id_next;
+ for (id = lbarray[lba_idx]->first; id; id = id_next) {
+ id_next = id->next;
+ /* XXX That check may be a bit to generic/permissive? */
+ if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
+ BKE_libblock_free(bmain, id);
+ }
+ }
+ }
+
+ /* Get rid of no more used libraries... */
+ BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id;
+ for (id = lbarray[lba_idx]->first; id; id = id->next) {
+ if (id->lib) {
+ id->lib->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ Library *lib, *lib_next;
+ for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
+ lib_next = lib->id.next;
+ if (lib->id.tag & LIB_TAG_DOIT) {
+ id_us_clear_real(&lib->id);
+ if (lib->id.us == 0) {
+ BKE_libblock_free(bmain, (ID *)lib);
+ }
+ }
+ }
+}
+
+static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
+{
+ Library *lib;
+ char lib_name[MAX_NAME];
+
+ RNA_string_get(op->ptr, "library", lib_name);
+ lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name);
+
+ if (lib) {
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
+ WMLinkAppendData *lapp_data;
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ int lba_idx;
+
+ char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ short flag = 0;
+
+ if (RNA_boolean_get(op->ptr, "relative_path")) {
+ flag |= FILE_RELPATH;
+ }
+
+ if (lib->parent && !do_reload) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot relocate indirectly linked library '%s'", lib->filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_string_get(op->ptr, "directory", root);
+ RNA_string_get(op->ptr, "filename", libname);
+
+ if (!BLO_has_bfile_extension(libname)) {
+ BKE_report(op->reports, RPT_ERROR, "Not a library");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_join_dirfile(path, sizeof(path), root, libname);
+
+ if (!BLI_exists(path)) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Trying to reload or relocate library '%s' to invalid path '%s'", lib->id.name, path);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BLI_path_cmp(lib->filepath, path) == 0) {
+#ifdef PRINT_DEBUG
+ printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us);
+#endif
+
+ do_reload = true;
+
+ lapp_data = wm_link_append_data_new(flag);
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ else {
+ int totfiles = 0;
+
+#ifdef PRINT_DEBUG
+ printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname);
+#endif
+
+ /* Check if something is indicated for relocate. */
+ prop = RNA_struct_find_property(op->ptr, "files");
+ if (prop) {
+ totfiles = RNA_property_collection_length(op->ptr, prop);
+ if (totfiles == 0) {
+ if (!libname[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+
+ lapp_data = wm_link_append_data_new(flag);
+
+ if (totfiles) {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) {
+ continue;
+ }
+
+#ifdef PRINT_DEBUG
+ printf("\t candidate new lib to reload datablocks from: %s\n", path);
+#endif
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ RNA_END;
+ }
+ else {
+#ifdef PRINT_DEBUG
+ printf("\t candidate new lib to reload datablocks from: %s\n", path);
+#endif
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ }
+
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == lib) {
+ WMLinkAppendDataItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
+ BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
+
+#ifdef PRINT_DEBUG
+ printf("\tdatablock to seek for: %s\n", id->name);
+#endif
+ }
+ }
+ }
+
+ lib_relocate_do(bmain, lapp_data, op->reports, do_reload);
+
+ wm_link_append_data_free(lapp_data);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
+ BLI_strncpy(G.lib, root, FILE_MAX);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_lib_relocate_exec(bContext *C, wmOperator *op)
+{
+ return wm_lib_relocate_exec_do(C, op, false);
+}
+
+void WM_OT_lib_relocate(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Relocate Library";
+ ot->idname = "WM_OT_lib_relocate";
+ ot->description = "Relocate the given library to one or several others";
+
+ ot->invoke = wm_lib_relocate_invoke;
+ ot->exec = wm_lib_relocate_exec;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+static int wm_lib_reload_exec(bContext *C, wmOperator *op)
+{
+ return wm_lib_relocate_exec_do(C, op, true);
+}
+
+void WM_OT_lib_reload(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Reload Library";
+ ot->idname = "WM_OT_lib_reload";
+ ot->description = "Reload the given library";
+
+ ot->exec = wm_lib_reload_exec;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 26d1d4c3266..1357729e898 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -233,19 +233,15 @@ static void wm_gesture_draw_circle(wmGesture *gt)
}
struct LassoFillData {
- unsigned int *px;
+ unsigned char *px;
int width;
};
static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
{
struct LassoFillData *data = user_data;
- unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]);
- do {
- col[0] = col[1] = col[2] = 0xff;
- col[3] = 0x10;
- col += 4;
- } while (++x != x_end);
+ unsigned char *col = &(data->px[(y * data->width) + x]);
+ memset(col, 0x10, x_end - x);
}
static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
@@ -273,7 +269,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
if (BLI_rcti_is_empty(&rect) == false) {
const int w = BLI_rcti_size_x(&rect);
const int h = BLI_rcti_size_y(&rect);
- unsigned int *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
+ unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
struct LassoFillData lasso_fill_data = {pixel_buf, w};
fill_poly_v2i_n(
@@ -281,14 +277,27 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
(const int (*)[2])moves, tot,
draw_filled_lasso_px_cb, &lasso_fill_data);
- glEnable(GL_BLEND);
- // glColor4f(1.0, 1.0, 1.0, 0.05);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glRasterPos2f(rect.xmin, rect.ymin);
+ glColor4f(1, 1, 1, 1);
+ glPixelTransferf(GL_RED_BIAS, 1);
+ glPixelTransferf(GL_GREEN_BIAS, 1);
+ glPixelTransferf(GL_BLUE_BIAS, 1);
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+ glEnable(GL_BLEND);
+ glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
glDisable(GL_BLEND);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+
+ glPixelTransferf(GL_RED_BIAS, 0);
+ glPixelTransferf(GL_GREEN_BIAS, 0);
+ glPixelTransferf(GL_BLUE_BIAS, 0);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
MEM_freeN(pixel_buf);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 6300d2ed3c7..9d1083bbf63 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -61,6 +61,7 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
@@ -140,6 +141,11 @@ static void wm_free_reports(bContext *C)
BKE_reports_clear(reports);
}
+static void wm_undo_kill_callback(bContext *C)
+{
+ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+}
+
bool wm_start_with_console = false; /* used in creator.c */
/* only called once, for startup */
@@ -158,11 +164,13 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
+ BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
+
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
- BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */
+ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
- BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
+ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
DAG_editors_update_cb(ED_render_id_flush_update,
ED_render_scene_update,
ED_render_scene_update_pre); /* depsgraph.c */
@@ -533,7 +541,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
#ifdef WITH_PYTHON
/* option not to close python so we can use 'atexit' */
- if (do_python) {
+ if (do_python && ((C == NULL) || CTX_py_init_get(C))) {
/* XXX - old note */
/* before BKE_blender_free so py's gc happens while library still exists */
/* needed at least for a rare sigsegv that can happen in pydrivers */
@@ -578,6 +586,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLI_threadapi_exit();
+ BKE_blender_atexit();
+
if (MEM_get_memory_blocks_in_use() != 0) {
size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b4295bb2607..8968c2a4543 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1391,7 +1391,7 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
}
}
-static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
+static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
{
wmOperator *op = op_ptr;
if (op->type->check) {
@@ -1423,7 +1423,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, dialog_check_cb, op, NULL);
+ UI_block_func_set(block, popup_check_cb, op, NULL);
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
@@ -1463,9 +1463,13 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
+ UI_block_func_set(block, popup_check_cb, op, NULL);
+
/* since ui is defined the auto-layout args are not used */
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
+ UI_block_func_set(block, NULL, NULL, NULL);
+
UI_block_bounds_set_popup(block, 4, 0, 0);
return block;
@@ -4123,6 +4127,8 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_revert_mainfile);
WM_operatortype_append(WM_OT_link);
WM_operatortype_append(WM_OT_append);
+ WM_operatortype_append(WM_OT_lib_relocate);
+ WM_operatortype_append(WM_OT_lib_reload);
WM_operatortype_append(WM_OT_recover_last_session);
WM_operatortype_append(WM_OT_recover_auto_save);
WM_operatortype_append(WM_OT_save_as_mainfile);
@@ -4202,7 +4208,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
- WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle");
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 6526d419914..458ac4a121a 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/* *************************** Framebuffer color depth, for selection codes ********************** */
-
-#ifdef __APPLE__
-
-/* apple seems to round colors to below and up on some configs */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x070707;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x030303;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x010101;
- break;
- }
-
- return i;
-}
-
-#else
-
-/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 8:
- i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
- i |= 0x3F3F3F;
- break;
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x0F0F0F;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x070707;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x030303;
- break;
- }
-
- return i;
-}
-
-#endif
-
-void WM_framebuffer_index_set(int index)
-{
- const int col = index_to_framebuffer(index);
- cpack(col);
-}
-
-void WM_framebuffer_index_get(int index, int *r_col)
-{
- const int col = index_to_framebuffer(index);
- char *c_col = (char *)r_col;
- c_col[0] = (col & 0xFF); /* red */
- c_col[1] = ((col >> 8) & 0xFF); /* green */
- c_col[2] = ((col >> 16) & 0xFF); /* blue */
- c_col[3] = 0xFF; /* alpha */
-}
-
-
-
-#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6))
-#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4))
-#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3))
-#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2))
-#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF)
-
-int WM_framebuffer_to_index(unsigned int col)
-{
- if (col == 0) {
- return 0;
- }
-
- switch (GPU_color_depth()) {
- case 8: return INDEX_FROM_BUF_8(col);
- case 12: return INDEX_FROM_BUF_12(col);
- case 15:
- case 16: return INDEX_FROM_BUF_15_16(col);
- case 24: return INDEX_FROM_BUF_24(col);
- default: return INDEX_FROM_BUF_18(col);
- }
-}
-
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size)
-{
-#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
- for (i = size; i--; col++) { \
- if ((c = *col)) { \
- *col = INDEX_FROM_BUF_BITS(c); \
- } \
- } ((void)0)
-
- if (size > 0) {
- unsigned int i, c;
-
- switch (GPU_color_depth()) {
- case 8:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
- break;
- case 12:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
- break;
- case 15:
- case 16:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
- break;
- case 24:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
- break;
- default:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
- break;
- }
- }
-
-#undef INDEX_BUF_ARRAY
-}
-
-
/* ********** END MY WINDOW ************** */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index e2b95da29a1..3085f138846 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -311,14 +311,17 @@ enum {
TIMERNOTIFIER = 0x0118, /* timer event, notifier sender */
TIMERF = 0x011F, /* last timer */
- /* Tweak, gestures: 0x500x, 0x501x */
+ /* Actionzones, tweak, gestures: 0x500x, 0x501x */
EVT_ACTIONZONE_AREA = 0x5000,
EVT_ACTIONZONE_REGION = 0x5001,
EVT_ACTIONZONE_FULLSCREEN = 0x5011,
/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
- /* tweak events, for L M R mousebuttons */
+ /* Tweak events:
+ * Sent as additional event with the mouse coordinates from where the initial click was placed. */
+
+ /* tweak events for L M R mousebuttons */
EVT_TWEAK_L = 0x5002,
EVT_TWEAK_M = 0x5003,
EVT_TWEAK_R = 0x5004,
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 2eae9cdb012..396907a3f6d 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -59,5 +59,8 @@ void WM_OT_save_mainfile(struct wmOperatorType *ot);
void WM_OT_link(struct wmOperatorType *ot);
void WM_OT_append(struct wmOperatorType *ot);
+void WM_OT_lib_relocate(struct wmOperatorType *ot);
+void WM_OT_lib_reload(struct wmOperatorType *ot);
+
#endif /* __WM_FILES_H__ */
diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h
index 2a8118a726b..cc9abf87514 100644
--- a/source/blender/windowmanager/wm_subwindow.h
+++ b/source/blender/windowmanager/wm_subwindow.h
@@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]);
void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect);
void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect);
-unsigned int index_to_framebuffer(int index);
-
#endif /* __WM_SUBWINDOW_H__ */
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 6f32d50c2fe..206007b8d8b 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -215,6 +215,14 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
endif()
+ if(WITH_GAMEENGINE_DECKLINK)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink)
+ endif()
+
+ if(WIN32)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect)
+ endif()
+
if(WITH_OPENSUBDIV)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 95abfdc4f4c..7c7958a4acd 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -326,8 +326,6 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO
void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE
void WM_uilisttype_free(void) RET_NONE
-void WM_framebuffer_index_get(int index, int *r_col) RET_NONE
-
struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE
@@ -380,7 +378,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE
void ED_render_engine_changed(struct Main *bmain) RET_NONE
void ED_file_read_bookmarks(void) RET_NONE
-void ED_file_change_dir(struct bContext *C, const bool checkdir) RET_NONE
+void ED_file_change_dir(struct bContext *C) RET_NONE
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE
struct FSMenu *ED_fsmenu_get(void) RET_NULL
struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) RET_NULL
@@ -526,7 +524,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
struct Main *bmain, struct Scene *scene, int flag) RET_NULL
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
struct Main *bmain, struct Scene *scene, int flag,
- struct ARegion *ar, struct View3D *v3d) RET_NULL
+ const struct ARegion *ar, const struct View3D *v3d) RET_NULL
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 122c10ef216..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.
@@ -338,6 +352,8 @@ if(WITH_PYTHON)
DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts
DESTINATION ${TARGETDIR_VER}
PATTERN ".git" EXCLUDE
+ PATTERN ".gitignore" EXCLUDE
+ PATTERN ".arcconfig" EXCLUDE
PATTERN "__pycache__" EXCLUDE
PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE
PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE
@@ -538,6 +554,7 @@ if(UNIX AND NOT APPLE)
DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}
PATTERN "__pycache__" EXCLUDE # * any cache *
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
PATTERN "lib2to3" EXCLUDE # ./lib2to3
PATTERN "site-packages/*" EXCLUDE # ./site-packages/*
PATTERN "tkinter" EXCLUDE # ./tkinter
@@ -914,6 +931,7 @@ elseif(APPLE)
PATTERN "__pycache__" EXCLUDE
PATTERN "__MACOSX" EXCLUDE
PATTERN ".DS_Store" EXCLUDE
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
)
endmacro()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 315d0d40243..e2761c9ef38 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -148,6 +148,35 @@ static void main_callback_setup(void)
MEM_set_error_callback(callback_mem_error);
}
+/* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */
+struct CreatorAtExitData {
+ bArgs *ba;
+#ifdef WIN32
+ const char **argv;
+ int argv_num;
+#endif
+};
+
+static void callback_main_atexit(void *user_data)
+{
+ struct CreatorAtExitData *app_init_data = user_data;
+
+ if (app_init_data->ba) {
+ BLI_argsFree(app_init_data->ba);
+ app_init_data->ba = NULL;
+ }
+
+#ifdef WIN32
+ if (app_init_data->argv) {
+ while (app_init_data->argv_num) {
+ free(app_init_data->argv[--app_init_data->argv_num]);
+ }
+ free(app_init_data->argv);
+ app_init_data->argv = NULL;
+ }
+#endif
+}
+
/** \} */
@@ -199,6 +228,9 @@ int main(
/* --- end declarations --- */
+ /* ensure we free data on early-exit */
+ struct CreatorAtExitData app_init_data = {NULL};
+ BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
#ifdef WIN32
/* We delay loading of openmp so we can set the policy here. */
@@ -222,6 +254,10 @@ int main(
argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0);
}
LocalFree(argv_16);
+
+ /* free on early-exit */
+ app_init_data.argv = argv;
+ app_init_data.argv_num = argv_num;
}
#endif /* WIN32 */
@@ -336,6 +372,10 @@ int main(
/* first test for background */
#ifndef WITH_PYTHON_MODULE
ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */
+
+ /* ensure we free on early exit */
+ app_init_data.ba = ba;
+
main_args_setup(C, ba, &syshandle);
BLI_argsParse(ba, 1, NULL, NULL);
@@ -432,16 +472,22 @@ int main(
#endif
+ /* Explicitly free data allocated for argument parsing:
+ * - 'ba'
+ * - 'argv' on WIN32.
+ */
+ callback_main_atexit(&app_init_data);
+ BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data);
+
+ /* paranoid, avoid accidental re-use */
#ifndef WITH_PYTHON_MODULE
- BLI_argsFree(ba);
+ ba = NULL;
+ (void)ba;
#endif
#ifdef WIN32
- while (argv_num) {
- free(argv[--argv_num]);
- }
- free(argv);
argv = NULL;
+ (void)argv;
#endif
#ifdef WITH_PYTHON_MODULE
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 3b27ad6f693..c89cdea4e29 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -72,6 +72,7 @@
#include "WM_api.h"
+#include "GPU_basic_shader.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
@@ -591,6 +592,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf("\n");
printf("Experimental Features:\n");
BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl");
printf("\n");
printf("Argument Parsing:\n");
@@ -1172,6 +1174,16 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar
return 0;
}
+static const char arg_handle_basic_shader_glsl_use_new_doc[] =
+"\n\tUse new GLSL basic shader"
+;
+static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf("Using new GLSL basic shader.\n");
+ GPU_basic_shader_use_glsl_set(true);
+ return 0;
+}
+
static const char arg_handle_verbosity_set_doc[] =
"<verbose>\n"
"\tSet logging verbosity level."
@@ -1807,6 +1819,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL);
BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index c5fc55a8e68..91683f4d6e7 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -341,6 +341,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
ketsjiengine->SetUseFixedTime(usefixed);
ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS);
+ ketsjiengine->SetRender(true);
KX_KetsjiEngine::SetExitKey(ConvertKeyCode(startscene->gm.exitkey));
//set the global settings (carried over if restart/load new files)
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 14dc0d71b83..4751e60996d 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -1366,7 +1366,7 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
/* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller
* and cant be apart of the parents compound shape, same goes for OB_SOFT_BODY */
if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) {
- if( (parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) {
+ if ((parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) {
isCompoundChild = true;
}
}
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index 455fef0aceb..974dcbca95b 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -394,8 +394,9 @@ void BL_ConvertActuators(const char* maggiename,
soundActuatorType);
// if we made it mono, we have to free it
- if(sound && snd_sound && snd_sound != sound->playback_handle)
+ if (sound && snd_sound && snd_sound != sound->playback_handle) {
AUD_Sound_free(snd_sound);
+ }
tmpsoundact->SetName(bact->name);
baseact = tmpsoundact;
diff --git a/source/gameengine/Expressions/EXP_PyObjectPlus.h b/source/gameengine/Expressions/EXP_PyObjectPlus.h
index dd612a08494..32dc79cf6eb 100644
--- a/source/gameengine/Expressions/EXP_PyObjectPlus.h
+++ b/source/gameengine/Expressions/EXP_PyObjectPlus.h
@@ -73,7 +73,7 @@ typedef struct {
wlink.warn_done = true; \
wlink.link = NULL; \
\
- if(wlink_last) { \
+ if (wlink_last) { \
wlink_last->link= (void *)&(wlink); \
PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \
} \
@@ -195,7 +195,7 @@ public: \
PyObject *Py##method_name(PyObject *args, PyObject *kwds); \
static PyObject * \
sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); \
@@ -208,7 +208,7 @@ public: \
PyObject *Py##method_name(PyObject *args); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -220,7 +220,7 @@ public: \
PyObject *Py##method_name(); \
static PyObject* \
sPy##method_name(PyObject *self) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -232,7 +232,7 @@ public: \
PyObject *Py##method_name(PyObject *value); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *value) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(value) - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -244,7 +244,7 @@ public: \
PyObject *Py##method_name(PyObject *args, PyObject *kwds); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(...) - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -257,7 +257,7 @@ public: \
PyObject *Py##method_name(PyObject *args); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(...) - " \
BGE_PROXY_ERROR_MSG); \
@@ -271,7 +271,7 @@ public: \
PyObject *Py##method_name(PyObject *value); \
static PyObject * \
sPy##method_name(PyObject *self, PyObject *value) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(value) - " \
BGE_PROXY_ERROR_MSG); \
@@ -285,7 +285,7 @@ public: \
PyObject *Py##method_name(); \
static PyObject * \
sPy##method_name(PyObject *self) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); \
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/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index 82f3bee86b2..abb64cf1733 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -199,7 +199,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
const float max = m_checkpropmaxval.ToFloat();
float val;
- if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE) {
val = orgprop->GetText().ToFloat();
}
else {
@@ -240,7 +240,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
const float ref = m_checkpropval.ToFloat();
float val;
- if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE) {
val = orgprop->GetText().ToFloat();
}
else {
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index f0a7bd47ca3..e697306e038 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -301,7 +301,7 @@ bool GPG_Application::startScreenSaverFullScreen(
const int stereoMode,
const GHOST_TUns16 samples)
{
- bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, samples);
+ bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, 0, samples);
if (ret)
{
HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
@@ -325,6 +325,7 @@ bool GPG_Application::startWindow(
int windowHeight,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples)
{
GHOST_GLSettings glSettings = {0};
@@ -333,6 +334,8 @@ bool GPG_Application::startWindow(
//STR_String title ("Blender Player - GHOST");
if (stereoVisual)
glSettings.flags |= GHOST_glStereoVisual;
+ if (alphaBackground)
+ glSettings.flags |= GHOST_glAlphaBackground;
glSettings.numOfAASamples = samples;
m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
@@ -360,6 +363,7 @@ bool GPG_Application::startEmbeddedWindow(
const GHOST_TEmbedderWindowID parentWindow,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples)
{
GHOST_TWindowState state = GHOST_kWindowStateNormal;
@@ -367,6 +371,8 @@ bool GPG_Application::startEmbeddedWindow(
if (stereoVisual)
glSettings.flags |= GHOST_glStereoVisual;
+ if (alphaBackground)
+ glSettings.flags |= GHOST_glAlphaBackground;
glSettings.numOfAASamples = samples;
if (parentWindow != 0)
@@ -394,6 +400,7 @@ bool GPG_Application::startFullScreen(
int bpp,int frequency,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples,
bool useDesktop)
{
@@ -407,7 +414,7 @@ bool GPG_Application::startFullScreen(
setting.bpp = bpp;
setting.frequency = frequency;
- fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, samples);
+ fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, alphaBackground, samples);
m_mainWindow->setCursorVisibility(false);
/* note that X11 ignores this (it uses a window internally for fullscreen) */
m_mainWindow->setState(GHOST_kWindowStateFullScreen);
@@ -626,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)
@@ -671,6 +680,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
//set the global settings (carried over if restart/load new files)
m_ketsjiengine->SetGlobalSettings(m_globalSettings);
+ m_ketsjiengine->SetRender(true);
m_engineInitialized = true;
}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h
index b6f545c2de8..e757cc10e32 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.h
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h
@@ -65,13 +65,13 @@ public:
bool startWindow(STR_String& title,
int windowLeft, int windowTop,
int windowWidth, int windowHeight,
- const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0);
bool startFullScreen(int width, int height,
int bpp, int frequency,
- const bool stereoVisual, const int stereoMode,
+ const bool stereoVisual, const int stereoMode, const int alphaBackground = 0,
const GHOST_TUns16 samples=0, bool useDesktop=false);
bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window,
- const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0);
#ifdef WIN32
bool startScreenSaverFullScreen(int width, int height,
int bpp, int frequency,
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index ac2e4dfa563..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"
{
@@ -74,6 +74,7 @@ extern "C"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_modifier.h"
#include "BKE_material.h"
#include "BKE_text.h"
@@ -102,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"
@@ -444,6 +445,7 @@ int main(
int validArguments=0;
bool samplesParFound = false;
GHOST_TUns16 aasamples = 0;
+ int alphaBackground = 0;
#ifdef WIN32
char **argv;
@@ -461,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 *));
@@ -838,6 +840,12 @@ int main(
}
break;
}
+ case 'a': // allow window to blend with display background
+ {
+ i++;
+ alphaBackground = 1;
+ break;
+ }
default: //not recognized
{
printf("Unknown argument: %s\n", argv[i++]);
@@ -1041,7 +1049,7 @@ int main(
#endif
{
app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
- stereoWindow, stereomode, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
+ stereoWindow, stereomode, alphaBackground, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
}
}
else
@@ -1088,7 +1096,7 @@ int main(
app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples);
else
app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
- stereoWindow, stereomode, aasamples);
+ stereoWindow, stereomode, alphaBackground, aasamples);
if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
GPU_set_mipmap(0);
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 6613780a0f8..72815cadc70 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -32,6 +32,7 @@
#include "MT_Matrix4x4.h"
#include "MT_Matrix3x3.h"
#include "KX_PyMath.h"
+#include "KX_PythonInit.h"
#include "MEM_guardedalloc.h"
#include "RAS_MeshObject.h"
@@ -67,15 +68,16 @@ BL_Uniform::~BL_Uniform()
#endif
}
-void BL_Uniform::Apply(class BL_Shader *shader)
+bool BL_Uniform::Apply(class BL_Shader *shader)
{
#ifdef SORT_UNIFORMS
+ RAS_IRasterizer *ras;
MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
- if (!mDirty) {
- return;
- }
+ if (!mDirty)
+ return false;
+ mDirty = false;
switch (mType) {
case UNI_FLOAT:
{
@@ -83,6 +85,15 @@ void BL_Uniform::Apply(class BL_Shader *shader)
glUniform1fARB(mLoc, (GLfloat)*f);
break;
}
+ case UNI_FLOAT_EYE:
+ {
+ float *f = (float*)mData;
+ ras = KX_GetActiveEngine()->GetRasterizer();
+ *f = (ras->GetEye() == RAS_IRasterizer::RAS_STEREO_LEFTEYE) ? 0.0f : 0.5f;
+ glUniform1fARB(mLoc, (GLfloat)*f);
+ mDirty = (ras->Stereo()) ? true : false;
+ break;
+ }
case UNI_INT:
{
int *f = (int *)mData;
@@ -138,7 +149,7 @@ void BL_Uniform::Apply(class BL_Shader *shader)
break;
}
}
- mDirty = false;
+ return mDirty;
#endif
}
@@ -274,11 +285,10 @@ void BL_Shader::ApplyShader()
return;
}
- for (unsigned int i = 0; i < mUniforms.size(); i++) {
- mUniforms[i]->Apply(this);
- }
-
mDirty = false;
+ for (unsigned int i=0; i<mUniforms.size(); i++) {
+ mDirty |= mUniforms[i]->Apply(this);
+ }
#endif
}
@@ -314,64 +324,70 @@ bool BL_Shader::LinkProgram()
return false;
}
- // -- vertex shader ------------------
- tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
- glShaderSourceARB(tmpVert, 1, (const char **)&vertProg, 0);
- glCompileShaderARB(tmpVert);
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&vertlen);
-
- // print info if any
- if (vertlen > 0 && vertlen < MAX_LOG_LEN) {
- logInf = (char *)MEM_mallocN(vertlen, "vert-log");
- glGetInfoLogARB(tmpVert, vertlen, (GLsizei *)&char_len, logInf);
-
- if (char_len > 0) {
- spit("---- Vertex Shader Error ----");
- spit(logInf);
+ if (vertProg[0] != 0) {
+ // -- vertex shader ------------------
+ tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
+ glCompileShaderARB(tmpVert);
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&vertlen);
+
+ // print info if any
+ if (vertlen > 0 && vertlen < MAX_LOG_LEN) {
+ logInf = (char*)MEM_mallocN(vertlen, "vert-log");
+ glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
+ if (char_len > 0) {
+ spit("---- Vertex Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf = 0;
+ }
+ // check for compile errors
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&vertstatus);
+ if (!vertstatus) {
+ spit("---- Vertex shader failed to compile ----");
+ goto programError;
}
-
- MEM_freeN(logInf);
- logInf = 0;
- }
-
- // check for compile errors
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&vertstatus);
- if (!vertstatus) {
- spit("---- Vertex shader failed to compile ----");
- goto programError;
}
- // -- fragment shader ----------------
- tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
- glShaderSourceARB(tmpFrag, 1, (const char **)&fragProg, 0);
- glCompileShaderARB(tmpFrag);
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&fraglen);
-
- if (fraglen > 0 && fraglen < MAX_LOG_LEN) {
- logInf = (char *)MEM_mallocN(fraglen, "frag-log");
- glGetInfoLogARB(tmpFrag, fraglen, (GLsizei *)&char_len, logInf);
-
- if (char_len > 0) {
- spit("---- Fragment Shader Error ----");
- spit(logInf);
+ if (fragProg[0] != 0) {
+ // -- fragment shader ----------------
+ tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ glShaderSourceARB(tmpFrag, 1, (const char**)&fragProg, 0);
+ glCompileShaderARB(tmpFrag);
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&fraglen);
+ if (fraglen > 0 && fraglen < MAX_LOG_LEN) {
+ logInf = (char*)MEM_mallocN(fraglen, "frag-log");
+ glGetInfoLogARB(tmpFrag, fraglen, (GLsizei*)&char_len, logInf);
+ if (char_len > 0) {
+ spit("---- Fragment Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf = 0;
}
- MEM_freeN(logInf);
- logInf = 0;
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&fragstatus);
+ if (!fragstatus) {
+ spit("---- Fragment shader failed to compile ----");
+ goto programError;
+ }
}
-
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&fragstatus);
-
- if (!fragstatus) {
- spit("---- Fragment shader failed to compile ----");
+
+ if (!tmpFrag && !tmpVert) {
+ spit("---- No shader given ----");
goto programError;
}
// -- program ------------------------
// set compiled vert/frag shader & link
tmpProg = glCreateProgramObjectARB();
- glAttachObjectARB(tmpProg, tmpVert);
- glAttachObjectARB(tmpProg, tmpFrag);
+ if (tmpVert) {
+ glAttachObjectARB(tmpProg, tmpVert);
+ }
+ if (tmpFrag) {
+ glAttachObjectARB(tmpProg, tmpFrag);
+ }
glLinkProgramARB(tmpProg);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&proglen);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint *)&progstatus);
@@ -396,8 +412,12 @@ bool BL_Shader::LinkProgram()
// set
mShader = tmpProg;
- glDeleteObjectARB(tmpVert);
- glDeleteObjectARB(tmpFrag);
+ if (tmpVert) {
+ glDeleteObjectARB(tmpVert);
+ }
+ if (tmpFrag) {
+ glDeleteObjectARB(tmpFrag);
+ }
mOk = 1;
mError = 0;
return true;
@@ -748,6 +768,7 @@ PyMethodDef BL_Shader::Methods[] = {
KX_PYMETHODTABLE(BL_Shader, validate),
// access functions
KX_PYMETHODTABLE(BL_Shader, isValid),
+ KX_PYMETHODTABLE(BL_Shader, setUniformEyef),
KX_PYMETHODTABLE(BL_Shader, setUniform1f),
KX_PYMETHODTABLE(BL_Shader, setUniform2f),
KX_PYMETHODTABLE(BL_Shader, setUniform3f),
@@ -1019,6 +1040,27 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
return NULL;
}
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformEyef, "setUniformEyef(name)")
+{
+ if (mError) {
+ Py_RETURN_NONE;
+ }
+ const char *uniform;
+ float value = 0.0f;
+ if (PyArg_ParseTuple(args, "s:setUniformEyef", &uniform)) {
+ int loc = GetUniformLocation(uniform);
+ if (loc != -1) {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT_EYE, &value, sizeof(float));
+#else
+ SetUniform(loc, (int)value);
+#endif
+ }
+ Py_RETURN_NONE;
+ }
+ return NULL;
+}
+
KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)")
{
if (mError) {
diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h
index aef4b42a85a..5de715d67d4 100644
--- a/source/gameengine/Ketsji/BL_Shader.h
+++ b/source/gameengine/Ketsji/BL_Shader.h
@@ -64,10 +64,11 @@ public:
UNI_FLOAT4,
UNI_MAT3,
UNI_MAT4,
+ UNI_FLOAT_EYE,
UNI_MAX
};
- void Apply(class BL_Shader *shader);
+ bool Apply(class BL_Shader *shader);
void SetData(int location, int type, bool transpose = false);
int GetLocation() { return mLoc; }
void *getData() { return mData; }
@@ -226,6 +227,7 @@ public:
KX_PYMETHOD_DOC(BL_Shader, setUniform3i);
KX_PYMETHOD_DOC(BL_Shader, setUniform2i);
KX_PYMETHOD_DOC(BL_Shader, setUniform1i);
+ KX_PYMETHOD_DOC(BL_Shader, setUniformEyef);
KX_PYMETHOD_DOC(BL_Shader, setUniformfv);
KX_PYMETHOD_DOC(BL_Shader, setUniformiv);
KX_PYMETHOD_DOC(BL_Shader, setUniformMatrix4);
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index 6585b9dc831..d08372e47d4 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -1600,7 +1600,7 @@ void KX_Dome::RotateCamera(KX_Camera* cam, int i)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
@@ -2035,7 +2035,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0f);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), 1.0f);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index 69c1af35bd9..3244400e1bd 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -142,7 +142,7 @@ KX_GameObject::~KX_GameObject()
}
// Unregister collision callbacks
// Do this before we start freeing physics information like m_pClient_info
- if (m_collisionCallbacks){
+ if (m_collisionCallbacks) {
UnregisterCollisionCallbacks();
Py_CLEAR(m_collisionCallbacks);
}
@@ -1564,7 +1564,7 @@ void KX_GameObject::UnregisterCollisionCallbacks()
PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment();
PHY_IPhysicsController* spc = GetPhysicsController();
// If we are the last to unregister on this physics controller
- if (pe->RemoveCollisionCallback(spc)){
+ if (pe->RemoveCollisionCallback(spc)) {
// If we are a sensor object
if (m_pClient_info->isSensor())
// Remove sensor body from physics world
@@ -1584,7 +1584,7 @@ void KX_GameObject::RegisterCollisionCallbacks()
PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment();
PHY_IPhysicsController* spc = GetPhysicsController();
// If we are the first to register on this physics controller
- if (pe->RequestCollisionCallback(spc)){
+ if (pe->RequestCollisionCallback(spc)) {
// If we are a sensor object
if (m_pClient_info->isSensor())
// Add sensor body to physics world
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 7237c473332..b0a8e376eb6 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -108,7 +108,7 @@ double KX_KetsjiEngine::m_suspendeddelta = 0.0;
double KX_KetsjiEngine::m_average_framerate = 0.0;
bool KX_KetsjiEngine::m_restrict_anim_fps = false;
short KX_KetsjiEngine::m_exitkey = 130; // ESC Key
-
+bool KX_KetsjiEngine::m_doRender = true;
/**
* Constructor of the Ketsji Engine
@@ -173,6 +173,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_overrideFrameColorR(0.0f),
m_overrideFrameColorG(0.0f),
m_overrideFrameColorB(0.0f),
+ m_overrideFrameColorA(0.0f),
m_usedome(false)
{
@@ -381,7 +382,7 @@ void KX_KetsjiEngine::RenderDome()
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
- 1.0
+ m_overrideFrameColorA
);
}
else
@@ -749,6 +750,9 @@ bool KX_KetsjiEngine::NextFrame()
scene->setSuspendedTime(m_clockTime);
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+
+ // invalidates the shadow buffer from previous render/ImageRender because the scene has changed
+ scene->SetShadowDone(false);
}
// update system devices
@@ -771,7 +775,7 @@ bool KX_KetsjiEngine::NextFrame()
// Start logging time spent outside main loop
m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
- return doRender;
+ return doRender && m_doRender;
}
@@ -805,7 +809,7 @@ void KX_KetsjiEngine::Render()
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
- 1.0
+ m_overrideFrameColorA
);
}
else
@@ -1133,6 +1137,8 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
cam->Release();
}
}
+ /* remember that we have a valid shadow buffer for that scene */
+ scene->SetShadowDone(true);
}
// update graphics
@@ -1252,7 +1258,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
cam->SetModelviewMatrix(viewmat);
// The following actually reschedules all vertices to be
@@ -1925,6 +1931,16 @@ short KX_KetsjiEngine::GetExitKey()
return m_exitkey;
}
+void KX_KetsjiEngine::SetRender(bool render)
+{
+ m_doRender = render;
+}
+
+bool KX_KetsjiEngine::GetRender()
+{
+ return m_doRender;
+}
+
void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
{
m_show_framerate = frameRate;
@@ -2023,19 +2039,21 @@ bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
}
-void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
+void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a)
{
m_overrideFrameColorR = r;
m_overrideFrameColorG = g;
m_overrideFrameColorB = b;
+ m_overrideFrameColorA = a;
}
-void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
+void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const
{
r = m_overrideFrameColorR;
g = m_overrideFrameColorG;
b = m_overrideFrameColorB;
+ a = m_overrideFrameColorA;
}
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index 3b8cec2ac82..1756214b6dd 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -129,6 +129,8 @@ private:
static short m_exitkey; /* Key used to exit the BGE */
+ static bool m_doRender; /* whether or not the scene should be rendered after the logic frame */
+
int m_exitcode;
STR_String m_exitstring;
@@ -199,6 +201,8 @@ private:
float m_overrideFrameColorG;
/** Blue component of framing bar color. */
float m_overrideFrameColorB;
+ /** alpha component of framing bar color. */
+ float m_overrideFrameColorA;
/** Settings that doesn't go away with Game Actuator */
GlobalSettings m_globalsettings;
@@ -209,7 +213,6 @@ private:
void RenderFrame(KX_Scene* scene, KX_Camera* cam);
void PostRenderScene(KX_Scene* scene);
void RenderDebugProperties();
- void RenderShadowBuffers(KX_Scene *scene);
public:
KX_KetsjiEngine(class KX_ISystem* system);
@@ -249,6 +252,7 @@ public:
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
+ void RenderShadowBuffers(KX_Scene *scene);
void StartEngine(bool clearIpo);
void StopEngine();
@@ -401,6 +405,16 @@ public:
static short GetExitKey();
/**
+ * Activate or deactivates the render of the scene after the logic frame
+ * \param render true (render) or false (do not render)
+ */
+ static void SetRender(bool render);
+ /**
+ * Get the current render flag value
+ */
+ static bool GetRender();
+
+ /**
* \Sets the display for frame rate on or off.
*/
void SetShowFramerate(bool frameRate);
@@ -485,7 +499,7 @@ public:
* \param g Green component of the override color.
* \param b Blue component of the override color.
*/
- void SetOverrideFrameColor(float r, float g, float b);
+ void SetOverrideFrameColor(float r, float g, float b, float a);
/**
* Returns the color used for framing bar color instead of the one in the Blender file's scenes.
@@ -493,7 +507,7 @@ public:
* \param g Green component of the override color.
* \param b Blue component of the override color.
*/
- void GetOverrideFrameColor(float& r, float& g, float& b) const;
+ void GetOverrideFrameColor(float& r, float& g, float& b, float& a) const;
KX_Scene* CreateScene(const STR_String& scenename);
KX_Scene* CreateScene(Scene *scene, bool libloading=false);
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 9ccf60b15ce..5f490747c2b 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -195,7 +195,7 @@ int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *att
PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name);
return PY_SET_ATTR_FAIL;
}
- else if(layer > MAX_LIGHT_LAYERS) {
+ else if (layer > MAX_LIGHT_LAYERS) {
PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name);
return PY_SET_ATTR_FAIL;
}
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 9f173a567ee..cdc2f9f3644 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -104,6 +104,7 @@ extern "C" {
#include "BL_ArmatureObject.h"
#include "RAS_IRasterizer.h"
#include "RAS_ICanvas.h"
+#include "RAS_IOffScreen.h"
#include "RAS_BucketManager.h"
#include "RAS_2DFilterManager.h"
#include "MT_Vector3.h"
@@ -469,6 +470,21 @@ static PyObject *gPyGetExitKey(PyObject *)
return PyLong_FromLong(KX_KetsjiEngine::GetExitKey());
}
+static PyObject *gPySetRender(PyObject *, PyObject *args)
+{
+ int render;
+ if (!PyArg_ParseTuple(args, "i:setRender", &render))
+ return NULL;
+ KX_KetsjiEngine::SetRender(render);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetRender(PyObject *)
+{
+ return PyBool_FromLong(KX_KetsjiEngine::GetRender());
+}
+
+
static PyObject *gPySetMaxLogicFrame(PyObject *, PyObject *args)
{
int frame;
@@ -909,6 +925,8 @@ static struct PyMethodDef game_methods[] = {
{"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"},
{"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"},
{"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"},
+ {"setRender", (PyCFunction) gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"},
+ {"getRender", (PyCFunction) gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"},
{"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"},
{"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"},
{"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. "
@@ -1457,6 +1475,158 @@ static PyObject *gPyGetDisplayDimensions(PyObject *)
return result;
}
+
+/* python wrapper around RAS_IOffScreen
+ * Should eventually gets its own file
+ */
+
+static void PyRASOffScreen__tp_dealloc(PyRASOffScreen *self)
+{
+ if (self->ofs)
+ delete self->ofs;
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+PyDoc_STRVAR(py_RASOffScreen_doc,
+"RASOffscreen(width, height) -> new GPU Offscreen object"
+"initialized to hold a framebuffer object of ``width`` x ``height``.\n"
+""
+);
+
+PyDoc_STRVAR(RASOffScreen_width_doc, "Offscreen buffer width.\n\n:type: integer");
+static PyObject *RASOffScreen_width_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetWidth());
+}
+
+PyDoc_STRVAR(RASOffScreen_height_doc, "Offscreen buffer height.\n\n:type: GLsizei");
+static PyObject *RASOffScreen_height_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetHeight());
+}
+
+PyDoc_STRVAR(RASOffScreen_color_doc, "Offscreen buffer texture object (if target is RAS_OFS_RENDER_TEXTURE).\n\n:type: GLuint");
+static PyObject *RASOffScreen_color_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetColor());
+}
+
+static PyGetSetDef RASOffScreen_getseters[] = {
+ {(char *)"width", (getter)RASOffScreen_width_get, (setter)NULL, RASOffScreen_width_doc, NULL},
+ {(char *)"height", (getter)RASOffScreen_height_get, (setter)NULL, RASOffScreen_height_doc, NULL},
+ {(char *)"color", (getter)RASOffScreen_color_get, (setter)NULL, RASOffScreen_color_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs)
+{
+ int width, height, samples, target;
+ const char *keywords[] = {"width", "height", "samples", "target", NULL};
+
+ samples = 0;
+ target = RAS_IOffScreen::RAS_OFS_RENDER_BUFFER;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target)) {
+ return -1;
+ }
+
+ if (width <= 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'width' given");
+ return -1;
+ }
+
+ if (height <= 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'height' given");
+ return -1;
+ }
+
+ if (samples < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'samples' given");
+ return -1;
+ }
+
+ if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid 'target' given, can only be RAS_OFS_RENDER_BUFFER or RAS_OFS_RENDER_TEXTURE");
+ return -1;
+ }
+ if (!gp_Rasterizer)
+ {
+ PyErr_SetString(PyExc_SystemError, "no rasterizer");
+ return -1;
+ }
+ self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target);
+ if (!self->ofs) {
+ PyErr_SetString(PyExc_SystemError, "creation failed");
+ return -1;
+ }
+ return 0;
+}
+
+PyTypeObject PyRASOffScreen_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "RASOffScreen", /* tp_name */
+ sizeof(PyRASOffScreen), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)PyRASOffScreen__tp_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ NULL, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ py_RASOffScreen_doc, /* Documentation string */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ RASOffScreen_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PyRASOffScreen__tp_init, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)PyType_GenericNew, /* tp_new */
+ (freefunc)0, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+ (destructor) NULL /* tp_del */
+};
+
+
+static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args)
+{
+ int width;
+ int height;
+ int samples;
+ int target;
+
+ samples = 0;
+ if (!PyArg_ParseTuple(args, "ii|ii:offScreenCreate", &width, &height, &samples, &target))
+ return NULL;
+
+ return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args);
+}
+
PyDoc_STRVAR(Rasterizer_module_documentation,
"This is the Python API for the game engine of Rasterizer"
);
@@ -1511,6 +1681,7 @@ static struct PyMethodDef rasterizer_methods[] = {
{"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"},
{"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"},
{"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"},
+ {"offScreenCreate", (PyCFunction) gPyOffScreenCreate, METH_VARARGS, "create an offscreen buffer object, arguments are width and height in pixels"},
{ NULL, (PyCFunction) NULL, 0, NULL }
};
@@ -2330,6 +2501,8 @@ PyMODINIT_FUNC initRasterizerPythonBinding()
PyObject *m;
PyObject *d;
+ PyType_Ready(&PyRASOffScreen_Type);
+
m = PyModule_Create(&Rasterizer_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m);
@@ -2357,6 +2530,11 @@ PyMODINIT_FUNC initRasterizerPythonBinding()
KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE);
KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
+ /* offscreen render */
+ KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_BUFFER, RAS_IOffScreen::RAS_OFS_RENDER_BUFFER);
+ KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_TEXTURE, RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE);
+
+
// XXXX Add constants here
// Check for errors
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index a5a418b5e78..c0d99d16a4c 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -172,6 +172,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_activity_culling = false;
m_suspend = false;
m_isclearingZbuffer = true;
+ m_isShadowDone = false;
m_tempObjectList = new CListValue();
m_objectlist = new CListValue();
m_parentlist = new CListValue();
@@ -1784,7 +1785,7 @@ void KX_Scene::UpdateObjectLods(void)
for (int i = 0; i < this->GetObjectList()->GetCount(); i++) {
gameobj = (KX_GameObject*) GetObjectList()->GetValue(i);
- if (!gameobj->GetCulled()){
+ if (!gameobj->GetCulled()) {
gameobj->UpdateLod(cam_pos);
}
}
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index c43b7be45dc..6d8ae8a321b 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -172,6 +172,11 @@ protected:
bool m_isclearingZbuffer;
/**
+ * Does the shadow buffer needs calculing
+ */
+ bool m_isShadowDone;
+
+ /**
* The name of the scene
*/
STR_String m_sceneName;
@@ -572,6 +577,8 @@ public:
bool IsSuspended();
bool IsClearingZBuffer();
void EnableZBufferClearing(bool isclearingZbuffer);
+ bool IsShadowDone() { return m_isShadowDone; }
+ void SetShadowDone(bool b) { m_isShadowDone = b; }
// use of DBVT tree for camera culling
void SetDbvtCulling(bool b) { m_dbvt_culling = b; }
bool GetDbvtCulling() { return m_dbvt_culling; }
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 1c42d65ae75..a27f37c0441 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -79,21 +79,18 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
KX_SoundActuator::~KX_SoundActuator()
{
- if(m_handle)
- {
+ if (m_handle) {
AUD_Handle_stop(m_handle);
}
- if(m_sound)
- {
+ if (m_sound) {
AUD_Sound_free(m_sound);
}
}
void KX_SoundActuator::play()
{
- if(m_handle)
- {
+ if (m_handle) {
AUD_Handle_stop(m_handle);
m_handle = NULL;
}
@@ -130,10 +127,8 @@ void KX_SoundActuator::play()
if(sound != m_sound)
AUD_Sound_free(sound);
- if (m_handle != NULL)
- {
- if (m_is3d)
- {
+ if (m_handle != NULL) {
+ if (m_is3d) {
AUD_Handle_setRelative(m_handle, true);
AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain);
AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain);
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
index beccdfaad93..a8fa9b0815d 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -207,7 +207,7 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr
vec = vec.safe_normalized_vec(z);
/* if 2D doesn't move the up vector */
- if (!threedimup){
+ if (!threedimup) {
vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f));
vec = (vec - z.dot(vec)*z).safe_normalized_vec(z);
}
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index c1af6de127e..ddae645802c 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -89,17 +89,17 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
if (gameOb->GetSGNode())
{
MT_Vector3 attachPos,attachDir,attachAxle;
- if(!PyVecTo(pylistPos,attachPos)) {
+ if (!PyVecTo(pylistPos,attachPos)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements.");
return NULL;
}
- if(!PyVecTo(pylistDir,attachDir)) {
+ if (!PyVecTo(pylistDir,attachDir)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements.");
return NULL;
}
- if(!PyVecTo(pylistAxleDir,attachAxle)) {
+ if (!PyVecTo(pylistAxleDir,attachAxle)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements.");
return NULL;
@@ -108,7 +108,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
//someone reverse some conventions inside Bullet (axle winding)
attachAxle = -attachAxle;
- if(wheelRadius<=0) {
+ if (wheelRadius <= 0) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. wheelRadius must be positive.");
return NULL;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index 58ea5e2e390..831e7346df7 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -430,7 +430,7 @@ public:
// PHY_ICharacter interface
virtual void Jump() { jump(); }
- virtual bool OnGround(){ return onGround(); }
+ virtual bool OnGround() { return onGround(); }
virtual float GetGravity() { return getGravity(); }
virtual void SetGravity(float gravity) { setGravity(gravity); }
virtual unsigned char GetMaxJumps() { return getMaxJumps(); }
@@ -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/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h
index 81c567ef08a..1a924904b7d 100644
--- a/source/gameengine/Physics/common/PHY_ICharacter.h
+++ b/source/gameengine/Physics/common/PHY_ICharacter.h
@@ -15,7 +15,7 @@
class PHY_ICharacter
{
public:
- virtual ~PHY_ICharacter(){};
+ virtual ~PHY_ICharacter() {};
virtual void Jump()= 0;
virtual bool OnGround()= 0;
diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h
index 284d77ca221..741fae8d2ad 100644
--- a/source/gameengine/Physics/common/PHY_IController.h
+++ b/source/gameengine/Physics/common/PHY_IController.h
@@ -48,7 +48,7 @@ class PHY_IPhysicsEnvironment;
class PHY_IController
{
public:
- virtual ~PHY_IController(){};
+ virtual ~PHY_IController() {};
// clientinfo for raycasts for example
virtual void* GetNewClientInfo()=0;
virtual void SetNewClientInfo(void* clientinfo)=0;
diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h
index d40b8da9451..e803d658713 100644
--- a/source/gameengine/Physics/common/PHY_IMotionState.h
+++ b/source/gameengine/Physics/common/PHY_IMotionState.h
@@ -44,7 +44,7 @@ class PHY_IMotionState
{
public:
- virtual ~PHY_IMotionState(){};
+ virtual ~PHY_IMotionState() {};
virtual void GetWorldPosition(float& posX,float& posY,float& posZ)=0;
virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0;
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
index 62b163536dd..4c6e8c71ef7 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h
@@ -53,7 +53,7 @@ class PHY_IPhysicsController : public PHY_IController
{
public:
- virtual ~PHY_IPhysicsController(){};
+ virtual ~PHY_IPhysicsController() {};
/**
* SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
*/
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index 2997048805f..72ec7b1edd0 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -116,7 +116,7 @@ public:
class PHY_IPhysicsEnvironment
{
public:
- virtual ~PHY_IPhysicsEnvironment(){}
+ virtual ~PHY_IPhysicsEnvironment() {}
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
/// Perform an integration step of duration 'timeStep'.
diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h
index 1dcec69a335..7e4a49e923e 100644
--- a/source/gameengine/Physics/common/PHY_IVehicle.h
+++ b/source/gameengine/Physics/common/PHY_IVehicle.h
@@ -18,7 +18,7 @@ class PHY_IMotionState;
class PHY_IVehicle
{
public:
- virtual ~PHY_IVehicle(){};
+ virtual ~PHY_IVehicle() {};
virtual void AddWheel(
PHY_IMotionState* motionState,
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index 496a864244b..c65fcac5161 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -65,6 +65,8 @@ set(SRC
RAS_IPolygonMaterial.h
RAS_IRasterizer.h
RAS_ILightObject.h
+ RAS_IOffScreen.h
+ RAS_ISync.h
RAS_MaterialBucket.h
RAS_MeshObject.h
RAS_ObjectColor.h
diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h
new file mode 100644
index 00000000000..d61a31504b8
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h
@@ -0,0 +1,84 @@
+/*
+ * ***** 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 RAS_IOffScreen.h
+ * \ingroup bgerast
+ */
+
+#ifndef __RAS_OFFSCREEN_H__
+#define __RAS_OFFSCREEN_H__
+
+#include "EXP_Python.h"
+
+class RAS_ICanvas;
+
+class MT_Transform;
+
+struct Image;
+
+class RAS_IOffScreen
+{
+public:
+ enum RAS_OFS_BIND_MODE {
+ RAS_OFS_BIND_RENDER = 0,
+ RAS_OFS_BIND_READ,
+ };
+ enum RAS_OFS_RENDER_TARGET {
+ RAS_OFS_RENDER_BUFFER = 0, // use render buffer as render target
+ RAS_OFS_RENDER_TEXTURE, // use texture as render target
+ };
+
+ int m_width;
+ int m_height;
+ int m_samples;
+ int m_color; // if used, holds the texture object, 0 if not used
+
+ virtual ~RAS_IOffScreen() {}
+
+ virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) = 0;
+ virtual void Destroy() = 0;
+ virtual void Bind(RAS_OFS_BIND_MODE mode) = 0;
+ virtual void Blit() = 0;
+ virtual void Unbind() = 0;
+ virtual void MipMap() = 0;
+
+ virtual int GetWidth() { return m_width; }
+ virtual int GetHeight() { return m_height; }
+ virtual int GetSamples() { return m_samples; }
+ virtual int GetColor() { return m_color; }
+};
+
+#ifdef WITH_PYTHON
+typedef struct {
+ PyObject_HEAD
+ RAS_IOffScreen *ofs;
+} PyRASOffScreen;
+
+extern PyTypeObject PyRASOffScreen_Type;
+#endif
+
+#endif /* __RAS_OFFSCREEN_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index a92b87773c7..dc92408915b 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -55,6 +55,8 @@ class RAS_IPolyMaterial;
class RAS_MeshSlot;
class RAS_ILightObject;
class SCA_IScene;
+class RAS_IOffScreen;
+class RAS_ISync;
typedef vector<unsigned short> KX_IndexArray;
typedef vector<RAS_TexVert> KX_VertexArray;
@@ -258,6 +260,18 @@ public:
virtual float GetFocalLength() = 0;
/**
+ * Create an offscreen render buffer that can be used as target for render.
+ * For the time being, it is only used in VideoTexture for custom render.
+ */
+ virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target) = 0;
+
+ /**
+ * Create a sync object
+ * For use with offscreen render
+ */
+ virtual RAS_ISync *CreateSync(int type) = 0;
+
+ /**
* SwapBuffers swaps the back buffer with the front buffer.
*/
virtual void SwapBuffers() = 0;
@@ -287,7 +301,7 @@ public:
* Sets the modelview matrix.
*/
virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori,
- const MT_Point3 &pos, bool perspective) = 0;
+ const MT_Point3 &pos, const MT_Vector3 &scale, bool perspective) = 0;
/**
*/
diff --git a/source/gameengine/Rasterizer/RAS_ISync.h b/source/gameengine/Rasterizer/RAS_ISync.h
new file mode 100644
index 00000000000..7e34172c2a3
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_ISync.h
@@ -0,0 +1,48 @@
+/*
+ * ***** 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 RAS_ISync.h
+ * \ingroup bgerast
+ */
+
+#ifndef __RAS_ISYNC_H__
+#define __RAS_ISYNC_H__
+
+class RAS_ISync
+{
+public:
+ enum RAS_SYNC_TYPE {
+ RAS_SYNC_TYPE_FENCE = 0,
+ };
+ virtual ~RAS_ISync() {}
+
+ virtual bool Create(RAS_SYNC_TYPE type) = 0;
+ virtual void Destroy() = 0;
+ virtual void Wait() = 0;
+};
+
+#endif /* __RAS_ISYNC_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
index 9f95e2c82af..89e31b62b41 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -51,6 +51,8 @@ set(INC_SYS
set(SRC
RAS_ListRasterizer.cpp
RAS_OpenGLLight.cpp
+ RAS_OpenGLOffScreen.cpp
+ RAS_OpenGLSync.cpp
RAS_OpenGLRasterizer.cpp
RAS_StorageVA.cpp
RAS_StorageVBO.cpp
@@ -58,6 +60,8 @@ set(SRC
RAS_IStorage.h
RAS_ListRasterizer.h
RAS_OpenGLLight.h
+ RAS_OpenGLOffScreen.h
+ RAS_OpenGLSync.h
RAS_OpenGLRasterizer.h
RAS_StorageVA.h
RAS_StorageVBO.h
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index 6f6513b001a..9190e8f2338 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -242,7 +242,7 @@ void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_T
RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
m_rasterizer->SetProjectionMatrix(projectionmat);
- m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
m_rasterizer->SetStereoMode(stereomode);
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
new file mode 100644
index 00000000000..e589bffcaf1
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -0,0 +1,347 @@
+/*
+ * ***** 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 *****
+ */
+
+#include "glew-mx.h"
+
+#include <stdio.h>
+
+#include "RAS_OpenGLOffScreen.h"
+#include "RAS_ICanvas.h"
+
+RAS_OpenGLOffScreen::RAS_OpenGLOffScreen(RAS_ICanvas *canvas)
+ :m_canvas(canvas), m_depthrb(0), m_colorrb(0), m_depthtx(0), m_colortx(0),
+ m_fbo(0), m_blitfbo(0), m_blitrbo(0), m_blittex(0), m_target(RAS_OFS_RENDER_BUFFER), m_bound(false)
+{
+ m_width = 0;
+ m_height = 0;
+ m_samples = 0;
+ m_color = 0;
+}
+
+RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen()
+{
+ Destroy();
+}
+
+bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target)
+{
+ GLenum status;
+ GLuint glo[2], fbo;
+ GLint max_samples;
+ GLenum textarget;
+
+ if (m_fbo) {
+ printf("RAS_OpenGLOffScreen::Create(): buffer exists already, destroy first\n");
+ return false;
+ }
+ if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER &&
+ target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE)
+ {
+ printf("RAS_OpenGLOffScreen::Create(): invalid offscren target\n");
+ return false;
+ }
+ if (!GLEW_EXT_framebuffer_object) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer not supported\n");
+ return false;
+ }
+ if (samples) {
+ if (!GLEW_EXT_framebuffer_multisample ||
+ !GLEW_EXT_framebuffer_blit)
+ {
+ samples = 0;
+ }
+ }
+ if (samples && target == RAS_OFS_RENDER_TEXTURE) {
+ // we need this in addition if we use multisample textures
+ if (!GLEW_ARB_texture_multisample ||
+ !GLEW_EXT_framebuffer_multisample_blit_scaled)
+ {
+ samples = 0;
+ }
+ }
+ if (samples) {
+ max_samples = 0;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT , &max_samples);
+ if (samples > max_samples)
+ samples = max_samples;
+ }
+ m_target = target;
+ fbo = 0;
+ glGenFramebuffersEXT(1, &fbo);
+ if (fbo == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer creation failed: %d\n", (int)glGetError());
+ return false;
+ }
+ m_fbo = fbo;
+ glo[0] = glo[1] = 0;
+ if (target == RAS_OFS_RENDER_TEXTURE) {
+ glGenTextures(2, glo);
+ if (glo[0] == 0 || glo[1] == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): texture creation failed: %d\n", (int)glGetError());
+ goto L_ERROR;
+ }
+ m_depthtx = glo[0];
+ m_color = m_colortx = glo[1];
+ if (samples) {
+ textarget = GL_TEXTURE_2D_MULTISAMPLE;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthtx);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT, width, height, true);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colortx);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ }
+ else {
+ textarget = GL_TEXTURE_2D;
+ glBindTexture(GL_TEXTURE_2D, m_depthtx);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, m_colortx);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, m_depthtx, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, m_colortx, 0);
+ }
+ else {
+ glGenRenderbuffersEXT(2, glo);
+ if (glo[0] == 0 || glo[1] == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): render buffer creation failed: %d\n", (int)glGetError());
+ goto L_ERROR;
+ }
+ m_depthrb = glo[0];
+ m_colorrb = glo[1];
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthrb);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_colorrb);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, m_depthrb);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_colorrb);
+ }
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer incomplete: %d\n", (int)status);
+ goto L_ERROR;
+ }
+ m_width = width;
+ m_height = height;
+
+ if (samples > 0) {
+ GLuint blit_tex;
+ GLuint blit_fbo;
+ // create a secondary FBO to blit to before the pixel can be read
+
+ /* write into new single-sample buffer */
+ glGenFramebuffersEXT(1, &blit_fbo);
+ if (!blit_fbo) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a FBO for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ m_blitfbo = blit_fbo;
+ blit_tex = 0;
+ if (target == RAS_OFS_RENDER_TEXTURE) {
+ glGenTextures(1, &blit_tex);
+ if (!blit_tex) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a texture for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ // m_color is the texture where the final render goes, the blit texture in this case
+ m_color = m_blittex = blit_tex;
+ glBindTexture(GL_TEXTURE_2D, m_blittex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_blittex, 0);
+ }
+ else {
+ /* create render buffer for new 'fbo_blit' */
+ glGenRenderbuffersEXT(1, &blit_tex);
+ if (!blit_tex) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a render buffer for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ m_blitrbo = blit_tex;
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_blitrbo);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo);
+ glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_blitrbo);
+ }
+ status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer for multi-sample offscreen buffer incomplete: %d\n", (int)status);
+ goto L_ERROR;
+ }
+ // remember that multisample is enabled
+ m_samples = 1;
+ }
+ return true;
+
+L_ERROR:
+ Destroy();
+ return false;
+}
+
+void RAS_OpenGLOffScreen::Destroy()
+{
+ GLuint globj;
+ Unbind();
+ if (m_fbo) {
+ globj = m_fbo;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ if (m_target == RAS_OFS_RENDER_TEXTURE) {
+ GLenum textarget = (m_samples) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, 0, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, 0, 0);
+ }
+ else {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDeleteFramebuffersEXT(1, &globj);
+ m_fbo = 0;
+ }
+ if (m_depthrb) {
+ globj = m_depthrb;
+ glDeleteRenderbuffers(1, &globj);
+ m_depthrb = 0;
+ }
+ if (m_colorrb) {
+ globj = m_colorrb;
+ glDeleteRenderbuffers(1, &globj);
+ m_colorrb = 0;
+ }
+ if (m_depthtx) {
+ globj = m_depthtx;
+ glDeleteTextures(1, &globj);
+ m_depthtx = 0;
+ }
+ if (m_colortx) {
+ globj = m_colortx;
+ glDeleteTextures(1, &globj);
+ m_colortx = 0;
+ }
+ if (m_blitfbo) {
+ globj = m_blitfbo;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_blitfbo);
+ if (m_target == RAS_OFS_RENDER_TEXTURE) {
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
+ }
+ else {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDeleteFramebuffersEXT(1, &globj);
+ m_blitfbo = 0;
+ }
+ if (m_blitrbo) {
+ globj = m_blitrbo;
+ glDeleteRenderbuffers(1, &globj);
+ m_blitrbo = 0;
+ }
+ if (m_blittex) {
+ globj = m_blittex;
+ glDeleteTextures(1, &globj);
+ m_blittex = 0;
+ }
+ m_width = 0;
+ m_height = 0;
+ m_samples = 0;
+ m_color = 0;
+ m_target = RAS_OFS_RENDER_BUFFER;
+}
+
+void RAS_OpenGLOffScreen::Bind(RAS_OFS_BIND_MODE mode)
+{
+ if (m_fbo) {
+ if (mode == RAS_OFS_BIND_RENDER) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glViewport(0, 0, m_width, m_height);
+ glDisable(GL_SCISSOR_TEST);
+ }
+ else if (!m_blitfbo) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ }
+ else {
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_blitfbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ }
+ m_bound = true;
+ }
+}
+
+void RAS_OpenGLOffScreen::Unbind()
+{
+ if (!m_bound)
+ return;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glEnable(GL_SCISSOR_TEST);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+ m_bound = false;
+}
+
+void RAS_OpenGLOffScreen::MipMap()
+{
+ if (m_color) {
+ glBindTexture(GL_TEXTURE_2D, m_color);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+void RAS_OpenGLOffScreen::Blit()
+{
+ if (m_bound && m_blitfbo) {
+ // set the draw target to the secondary FBO, the read target is still the multisample FBO
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m_blitfbo);
+
+ // sample the primary
+ glBlitFramebufferEXT(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // make sure the next glReadPixels will read from the secondary buffer
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, m_blitfbo);
+ }
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
new file mode 100644
index 00000000000..3f6845f1e21
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
@@ -0,0 +1,65 @@
+/*
+ * ***** 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 *****
+ */
+
+#ifndef __RAS_OPENGLOFFSCREEN__
+#define __RAS_OPENGLOFFSCREEN__
+
+#include "RAS_IOffScreen.h"
+#include "GPU_extensions.h"
+
+class RAS_ICanvas;
+
+class RAS_OpenGLOffScreen : public RAS_IOffScreen
+{
+ RAS_ICanvas *m_canvas;
+ // these are GL objects
+ unsigned int m_depthrb;
+ unsigned int m_colorrb;
+ unsigned int m_depthtx;
+ unsigned int m_colortx;
+ unsigned int m_fbo;
+ unsigned int m_blitfbo;
+ unsigned int m_blitrbo;
+ unsigned int m_blittex;
+ RAS_OFS_RENDER_TARGET m_target;
+ bool m_bound;
+
+
+public:
+ RAS_OpenGLOffScreen(RAS_ICanvas *canvas);
+ ~RAS_OpenGLOffScreen();
+
+ bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target);
+ void Destroy();
+ void Bind(RAS_OFS_BIND_MODE mode);
+ void Blit();
+ void Unbind();
+ void MipMap();
+};
+
+#endif /* __RAS_OPENGLOFFSCREEN__ */
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index ec6489ee13a..66c2fde908b 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -46,6 +46,8 @@
#include "MT_CmMatrix4x4.h"
#include "RAS_OpenGLLight.h"
+#include "RAS_OpenGLOffScreen.h"
+#include "RAS_OpenGLSync.h"
#include "RAS_StorageVA.h"
#include "RAS_StorageVBO.h"
@@ -92,6 +94,7 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE
m_time(0.0f),
m_campos(0.0f, 0.0f, 0.0f),
m_camortho(false),
+ m_camnegscale(false),
m_stereomode(RAS_STEREO_NOSTEREO),
m_curreye(RAS_STEREO_LEFTEYE),
m_eyeseparation(0.0f),
@@ -138,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();
}
@@ -207,7 +208,7 @@ void RAS_OpenGLRasterizer::SetBackColor(float color[3])
m_redback = color[0];
m_greenback = color[1];
m_blueback = color[2];
- m_alphaback = 1.0f;
+ m_alphaback = 0.0f;
}
void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, float color[3])
@@ -600,6 +601,31 @@ float RAS_OpenGLRasterizer::GetFocalLength()
return m_focallength;
}
+RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target)
+{
+ RAS_IOffScreen *ofs;
+
+ ofs = new RAS_OpenGLOffScreen(m_2DCanvas);
+
+ if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target)) {
+ delete ofs;
+ return NULL;
+ }
+ return ofs;
+}
+
+RAS_ISync *RAS_OpenGLRasterizer::CreateSync(int type)
+{
+ RAS_ISync *sync;
+
+ sync = new RAS_OpenGLSync();
+
+ if (!sync->Create((RAS_ISync::RAS_SYNC_TYPE)type)) {
+ delete sync;
+ return NULL;
+ }
+ return sync;
+}
void RAS_OpenGLRasterizer::SwapBuffers()
{
@@ -924,6 +950,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix(
void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
const MT_Matrix3x3 & camOrientMat3x3,
const MT_Point3 & pos,
+ const MT_Vector3 &scale,
bool perspective)
{
m_viewmatrix = mat;
@@ -966,6 +993,12 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
}
}
+ bool negX = (scale[0] < 0.0f);
+ bool negY = (scale[0] < 0.0f);
+ bool negZ = (scale[0] < 0.0f);
+ if (negX || negY || negZ) {
+ m_viewmatrix.tscale((negX)?-1.0f:1.0f, (negY)?-1.0f:1.0f, (negZ)?-1.0f:1.0f, 1.0);
+ }
m_viewinvmatrix = m_viewmatrix;
m_viewinvmatrix.invert();
@@ -976,6 +1009,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(glviewmat);
m_campos = pos;
+ m_camnegscale = negX ^ negY ^ negZ;
}
@@ -1108,6 +1142,9 @@ void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend)
void RAS_OpenGLRasterizer::SetFrontFace(bool ccw)
{
+ if (m_camnegscale)
+ ccw = !ccw;
+
if (m_last_frontface == ccw)
return;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index 4c22d1de611..9561e207dba 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -96,6 +96,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer
MT_Matrix4x4 m_viewinvmatrix;
MT_Point3 m_campos;
bool m_camortho;
+ bool m_camnegscale;
StereoMode m_stereomode;
StereoEye m_curreye;
@@ -180,7 +181,8 @@ public:
virtual float GetEyeSeparation();
virtual void SetFocalLength(const float focallength);
virtual float GetFocalLength();
-
+ virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target);
+ virtual RAS_ISync *CreateSync(int type);
virtual void SwapBuffers();
virtual void IndexPrimitives(class RAS_MeshSlot &ms);
@@ -189,7 +191,12 @@ public:
virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat);
virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat);
- virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori, const MT_Point3 &pos, bool perspective);
+ virtual void SetViewMatrix(
+ const MT_Matrix4x4 &mat,
+ const MT_Matrix3x3 &ori,
+ const MT_Point3 &pos,
+ const MT_Vector3 &scale,
+ bool perspective);
virtual const MT_Point3& GetCameraPosition();
virtual bool GetCameraOrtho();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
new file mode 100644
index 00000000000..d54b3232067
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
@@ -0,0 +1,82 @@
+/*
+ * ***** 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 *****
+ */
+
+#include "glew-mx.h"
+
+#include <stdio.h>
+
+#include "RAS_OpenGLSync.h"
+
+RAS_OpenGLSync::RAS_OpenGLSync()
+ :m_sync(NULL)
+{
+}
+
+RAS_OpenGLSync::~RAS_OpenGLSync()
+{
+ Destroy();
+}
+
+bool RAS_OpenGLSync::Create(RAS_SYNC_TYPE type)
+{
+ if (m_sync) {
+ printf("RAS_OpenGLSync::Create(): sync already exists, destroy first\n");
+ return false;
+ }
+ if (type != RAS_SYNC_TYPE_FENCE) {
+ printf("RAS_OpenGLSync::Create(): only RAS_SYNC_TYPE_FENCE are currently supported\n");
+ return false;
+ }
+ if (!GLEW_ARB_sync) {
+ printf("RAS_OpenGLSync::Create(): ARB_sync extension is needed to create sync object\n");
+ return false;
+ }
+ m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ if (!m_sync) {
+ printf("RAS_OpenGLSync::Create(): glFenceSync() failed");
+ return false;
+ }
+ return true;
+}
+
+void RAS_OpenGLSync::Destroy()
+{
+ if (m_sync) {
+ glDeleteSync(m_sync);
+ m_sync = NULL;
+ }
+}
+
+void RAS_OpenGLSync::Wait()
+{
+ if (m_sync) {
+ // this is needed to ensure that the sync is in the GPU
+ glFlush();
+ // block until the operation have completed
+ glWaitSync(m_sync, 0, GL_TIMEOUT_IGNORED);
+ }
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
new file mode 100644
index 00000000000..4ba96903856
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
@@ -0,0 +1,50 @@
+/*
+ * ***** 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 *****
+ */
+
+#ifndef __RAS_OPENGLSYNC__
+#define __RAS_OPENGLSYNC__
+
+
+#include "RAS_ISync.h"
+
+struct __GLsync;
+
+class RAS_OpenGLSync : public RAS_ISync
+{
+private:
+ struct __GLsync *m_sync;
+
+public:
+ RAS_OpenGLSync();
+ ~RAS_OpenGLSync();
+
+ virtual bool Create(RAS_SYNC_TYPE type);
+ virtual void Destroy();
+ virtual void Wait();
+};
+
+#endif /* __RAS_OPENGLSYNC__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
index 34fdca23ee6..a5a3170ed77 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
@@ -45,7 +45,7 @@ public:
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
+ virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;};
protected:
int m_drawingmode;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index 9cb3449bed5..4c8e4a8931c 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -76,7 +76,7 @@ public:
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
+ virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;};
protected:
int m_drawingmode;
diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt
index 4be9a9abe5c..1eb09b02e05 100644
--- a/source/gameengine/VideoTexture/CMakeLists.txt
+++ b/source/gameengine/VideoTexture/CMakeLists.txt
@@ -45,6 +45,9 @@ set(INC
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
+ ../../../intern/decklink
+ ../../../intern/gpudirect
+ ../../../intern/atomic
)
set(INC_SYS
@@ -68,8 +71,10 @@ set(SRC
ImageViewport.cpp
PyTypeList.cpp
Texture.cpp
+ DeckLink.cpp
VideoBase.cpp
VideoFFmpeg.cpp
+ VideoDeckLink.cpp
blendVideoTex.cpp
BlendType.h
@@ -87,8 +92,10 @@ set(SRC
ImageViewport.h
PyTypeList.h
Texture.h
+ DeckLink.h
VideoBase.h
VideoFFmpeg.h
+ VideoDeckLink.h
)
if(WITH_CODEC_FFMPEG)
@@ -100,7 +107,13 @@ if(WITH_CODEC_FFMPEG)
remove_strict_flags_file(
VideoFFmpeg.cpp
+ VideoDeckLink
+ DeckLink
)
endif()
+if(WITH_GAMEENGINE_DECKLINK)
+ add_definitions(-DWITH_GAMEENGINE_DECKLINK)
+endif()
+
blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h
index 90f7e66452a..22ea177addc 100644
--- a/source/gameengine/VideoTexture/Common.h
+++ b/source/gameengine/VideoTexture/Common.h
@@ -36,7 +36,8 @@
#define NULL 0
#endif
-#ifndef HRESULT
+#ifndef _HRESULT_DEFINED
+#define _HRESULT_DEFINED
#define HRESULT long
#endif
diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp
new file mode 100644
index 00000000000..fa8ab8c641c
--- /dev/null
+++ b/source/gameengine/VideoTexture/DeckLink.cpp
@@ -0,0 +1,813 @@
+/*
+ * ***** 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 gameengine/VideoTexture/Texture.cpp
+ * \ingroup bgevideotex
+ */
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+// implementation
+
+// FFmpeg defines its own version of stdint.h on Windows.
+// Decklink needs FFmpeg, so it uses its version of stdint.h
+// this is necessary for INT64_C macro
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+// this is necessary for UINTPTR_MAX (used by atomic-ops)
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+#include "atomic_ops.h"
+
+#include "EXP_PyObjectPlus.h"
+#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h"
+#include "DeckLink.h"
+
+#include <memory.h>
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); return NULL; }
+
+static struct
+{
+ const char *name;
+ BMDDisplayMode mode;
+} sModeStringTab[] = {
+ { "NTSC", bmdModeNTSC },
+ { "NTSC2398", bmdModeNTSC2398 },
+ { "PAL", bmdModePAL },
+ { "NTSCp", bmdModeNTSCp },
+ { "PALp", bmdModePALp },
+
+ /* HD 1080 Modes */
+
+ { "HD1080p2398", bmdModeHD1080p2398 },
+ { "HD1080p24", bmdModeHD1080p24 },
+ { "HD1080p25", bmdModeHD1080p25 },
+ { "HD1080p2997", bmdModeHD1080p2997 },
+ { "HD1080p30", bmdModeHD1080p30 },
+ { "HD1080i50", bmdModeHD1080i50 },
+ { "HD1080i5994", bmdModeHD1080i5994 },
+ { "HD1080i6000", bmdModeHD1080i6000 },
+ { "HD1080p50", bmdModeHD1080p50 },
+ { "HD1080p5994", bmdModeHD1080p5994 },
+ { "HD1080p6000", bmdModeHD1080p6000 },
+
+ /* HD 720 Modes */
+
+ { "HD720p50", bmdModeHD720p50 },
+ { "HD720p5994", bmdModeHD720p5994 },
+ { "HD720p60", bmdModeHD720p60 },
+
+ /* 2k Modes */
+
+ { "2k2398", bmdMode2k2398 },
+ { "2k24", bmdMode2k24 },
+ { "2k25", bmdMode2k25 },
+
+ /* DCI Modes (output only) */
+
+ { "2kDCI2398", bmdMode2kDCI2398 },
+ { "2kDCI24", bmdMode2kDCI24 },
+ { "2kDCI25", bmdMode2kDCI25 },
+
+ /* 4k Modes */
+
+ { "4K2160p2398", bmdMode4K2160p2398 },
+ { "4K2160p24", bmdMode4K2160p24 },
+ { "4K2160p25", bmdMode4K2160p25 },
+ { "4K2160p2997", bmdMode4K2160p2997 },
+ { "4K2160p30", bmdMode4K2160p30 },
+ { "4K2160p50", bmdMode4K2160p50 },
+ { "4K2160p5994", bmdMode4K2160p5994 },
+ { "4K2160p60", bmdMode4K2160p60 },
+ // sentinel
+ { NULL }
+};
+
+static struct
+{
+ const char *name;
+ BMDPixelFormat format;
+} sFormatStringTab[] = {
+ { "8BitYUV", bmdFormat8BitYUV },
+ { "10BitYUV", bmdFormat10BitYUV },
+ { "8BitARGB", bmdFormat8BitARGB },
+ { "8BitBGRA", bmdFormat8BitBGRA },
+ { "10BitRGB", bmdFormat10BitRGB },
+ { "12BitRGB", bmdFormat12BitRGB },
+ { "12BitRGBLE", bmdFormat12BitRGBLE },
+ { "10BitRGBXLE", bmdFormat10BitRGBXLE },
+ { "10BitRGBX", bmdFormat10BitRGBX },
+ // sentinel
+ { NULL }
+};
+
+ExceptionID DeckLinkBadDisplayMode, DeckLinkBadPixelFormat;
+ExpDesc DeckLinkBadDisplayModeDesc(DeckLinkBadDisplayMode, "Invalid or unsupported display mode");
+ExpDesc DeckLinkBadPixelFormatDesc(DeckLinkBadPixelFormat, "Invalid or unsupported pixel format");
+
+HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode)
+{
+ int i;
+
+ if (len == 0)
+ len = strlen(format);
+ for (i = 0; sModeStringTab[i].name != NULL; i++) {
+ if (strlen(sModeStringTab[i].name) == len &&
+ !strncmp(sModeStringTab[i].name, format, len))
+ {
+ *displayMode = sModeStringTab[i].mode;
+ return S_OK;
+ }
+ }
+ if (len != 4)
+ THRWEXCP(DeckLinkBadDisplayMode, S_OK);
+ // assume the user entered directly the mode value as a 4 char string
+ *displayMode = (BMDDisplayMode)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3]));
+ return S_OK;
+}
+
+HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *pixelFormat)
+{
+ int i;
+
+ if (!len)
+ len = strlen(format);
+ for (i = 0; sFormatStringTab[i].name != NULL; i++) {
+ if (strlen(sFormatStringTab[i].name) == len &&
+ !strncmp(sFormatStringTab[i].name, format, len))
+ {
+ *pixelFormat = sFormatStringTab[i].format;
+ return S_OK;
+ }
+ }
+ if (len != 4)
+ THRWEXCP(DeckLinkBadPixelFormat, S_OK);
+ // assume the user entered directly the mode value as a 4 char string
+ *pixelFormat = (BMDPixelFormat)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3]));
+ return S_OK;
+}
+
+class DeckLink3DFrameWrapper : public IDeckLinkVideoFrame, IDeckLinkVideoFrame3DExtensions
+{
+public:
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)
+ {
+ if (!memcmp(&iid, &IID_IDeckLinkVideoFrame3DExtensions, sizeof(iid))) {
+ if (mpRightEye) {
+ *ppv = (IDeckLinkVideoFrame3DExtensions*)this;
+ return S_OK;
+ }
+ }
+ return E_NOTIMPL;
+ }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1U; }
+ virtual ULONG STDMETHODCALLTYPE Release(void) { return 1U; }
+ // IDeckLinkVideoFrame
+ virtual long STDMETHODCALLTYPE GetWidth(void) { return mpLeftEye->GetWidth(); }
+ virtual long STDMETHODCALLTYPE GetHeight(void) { return mpLeftEye->GetHeight(); }
+ virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpLeftEye->GetRowBytes(); }
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpLeftEye->GetPixelFormat(); }
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpLeftEye->GetFlags(); }
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { return mpLeftEye->GetBytes(buffer); }
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,IDeckLinkTimecode **timecode)
+ { return mpLeftEye->GetTimecode(format, timecode); }
+ virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary)
+ { return mpLeftEye->GetAncillaryData(ancillary); }
+ // IDeckLinkVideoFrame3DExtensions
+ virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat(void)
+ {
+ return bmdVideo3DPackingLeftOnly;
+ }
+ virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye(
+ /* [out] */ IDeckLinkVideoFrame **rightEyeFrame)
+ {
+ mpRightEye->AddRef();
+ *rightEyeFrame = mpRightEye;
+ return S_OK;
+ }
+ // Constructor
+ DeckLink3DFrameWrapper(IDeckLinkVideoFrame *leftEye, IDeckLinkVideoFrame *rightEye)
+ {
+ mpLeftEye = leftEye;
+ mpRightEye = rightEye;
+ }
+ // no need for a destructor, it's just a wrapper
+private:
+ IDeckLinkVideoFrame *mpLeftEye;
+ IDeckLinkVideoFrame *mpRightEye;
+};
+
+static void decklink_Reset(DeckLink *self)
+{
+ self->m_lastClock = 0.0;
+ self->mDLOutput = NULL;
+ self->mUse3D = false;
+ self->mDisplayMode = bmdModeUnknown;
+ self->mKeyingSupported = false;
+ self->mHDKeyingSupported = false;
+ self->mSize[0] = 0;
+ self->mSize[1] = 0;
+ self->mFrameSize = 0;
+ self->mLeftFrame = NULL;
+ self->mRightFrame = NULL;
+ self->mKeyer = NULL;
+ self->mUseKeying = false;
+ self->mKeyingLevel = 255;
+ self->mUseExtend = false;
+}
+
+#ifdef __BIG_ENDIAN__
+#define CONV_PIXEL(i) ((((i)>>16)&0xFF00)+(((i)&0xFF00)<<16)+((i)&0xFF00FF))
+#else
+#define CONV_PIXEL(i) ((((i)&0xFF)<<16)+(((i)>>16)&0xFF)+((i)&0xFF00FF00))
+#endif
+
+// adapt the pixel format and picture size from VideoTexture (RGBA) to DeckLink (BGRA)
+static void decklink_ConvImage(uint32_t *dest, const short *destSize, const uint32_t *source, const short *srcSize, bool extend)
+{
+ short w, h, x, y;
+ const uint32_t *s;
+ uint32_t *d, p;
+ bool sameSize = (destSize[0] == srcSize[0] && destSize[1] == srcSize[1]);
+
+ if (sameSize || !extend) {
+ // here we convert pixel by pixel
+ w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0];
+ h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1];
+ for (y = 0; y < h; ++y) {
+ s = source + y*srcSize[0];
+ d = dest + y*destSize[0];
+ for (x = 0; x < w; ++x, ++s, ++d) {
+ *d = CONV_PIXEL(*s);
+ }
+ }
+ }
+ else {
+ // here we scale
+ // interpolation accumulator
+ int accHeight = srcSize[1] >> 1;
+ d = dest;
+ s = source;
+ // process image rows
+ for (y = 0; y < srcSize[1]; ++y) {
+ // increase height accum
+ accHeight += destSize[1];
+ // if pixel row has to be drawn
+ if (accHeight >= srcSize[1]) {
+ // decrease accum
+ accHeight -= srcSize[1];
+ // width accum
+ int accWidth = srcSize[0] >> 1;
+ // process row
+ for (x = 0; x < srcSize[0]; ++x, ++s) {
+ // increase width accum
+ accWidth += destSize[0];
+ // convert pixel
+ p = CONV_PIXEL(*s);
+ // if pixel has to be drown one or more times
+ while (accWidth >= srcSize[0]) {
+ // decrease accum
+ accWidth -= srcSize[0];
+ *d++ = p;
+ }
+ }
+ // if there should be more identical lines
+ while (accHeight >= srcSize[1]) {
+ accHeight -= srcSize[1];
+ // copy previous line
+ memcpy(d, d - destSize[0], 4 * destSize[0]);
+ d += destSize[0];
+ }
+ }
+ else {
+ // if we skip a source line
+ s += srcSize[0];
+ }
+ }
+ }
+}
+
+// DeckLink object allocation
+static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ // allocate object
+ DeckLink * self = reinterpret_cast<DeckLink*>(type->tp_alloc(type, 0));
+ // initialize object structure
+ decklink_Reset(self);
+ // m_leftEye is a python object, it's handled by python
+ self->m_leftEye = NULL;
+ self->m_rightEye = NULL;
+ // return allocated object
+ return reinterpret_cast<PyObject*>(self);
+}
+
+
+// forward declaration
+PyObject *DeckLink_close(DeckLink *self);
+int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure);
+
+
+// DeckLink object deallocation
+static void DeckLink_dealloc(DeckLink *self)
+{
+ // release renderer
+ Py_XDECREF(self->m_leftEye);
+ // close decklink
+ PyObject *ret = DeckLink_close(self);
+ Py_DECREF(ret);
+ // release object
+ Py_TYPE((PyObject *)self)->tp_free((PyObject *)self);
+}
+
+
+ExceptionID AutoDetectionNotAvail, DeckLinkOpenCard, DeckLinkBadFormat, DeckLinkInternalError;
+ExpDesc AutoDetectionNotAvailDesc(AutoDetectionNotAvail, "Auto detection not yet available");
+ExpDesc DeckLinkOpenCardDesc(DeckLinkOpenCard, "Cannot open card for output");
+ExpDesc DeckLinkBadFormatDesc(DeckLinkBadFormat, "Invalid or unsupported output format, use <mode>[/3D]");
+ExpDesc DeckLinkInternalErrorDesc(DeckLinkInternalError, "DeckLink API internal error, please report");
+
+// DeckLink object initialization
+static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
+{
+ IDeckLinkIterator* pIterator;
+ IDeckLinkAttributes* pAttributes;
+ IDeckLinkDisplayModeIterator* pDisplayModeIterator;
+ IDeckLinkDisplayMode* pDisplayMode;
+ IDeckLink* pDL;
+ char* p3D;
+ BOOL flag;
+ size_t len;
+ int i;
+ uint32_t displayFlags;
+ BMDVideoOutputFlags outputFlags;
+ BMDDisplayModeSupport support;
+ uint32_t* bytes;
+
+
+ // material ID
+ short cardIdx = 0;
+ // texture ID
+ char *format = NULL;
+
+ static const char *kwlist[] = {"cardIdx", "format", NULL};
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|hs",
+ const_cast<char**>(kwlist), &cardIdx, &format))
+ return -1;
+
+ try {
+ if (format == NULL) {
+ THRWEXCP(AutoDetectionNotAvail, S_OK);
+ }
+
+ if ((p3D = strchr(format, '/')) != NULL && strcmp(p3D, "/3D"))
+ THRWEXCP(DeckLinkBadFormat, S_OK);
+ self->mUse3D = (p3D) ? true : false;
+ // read the mode
+ len = (p3D) ? (size_t)(p3D - format) : strlen(format);
+ // throws if bad mode
+ decklink_ReadDisplayMode(format, len, &self->mDisplayMode);
+
+ pIterator = BMD_CreateDeckLinkIterator();
+ pDL = NULL;
+ if (pIterator) {
+ i = 0;
+ while (pIterator->Next(&pDL) == S_OK) {
+ if (i == cardIdx) {
+ break;
+ }
+ i++;
+ pDL->Release();
+ pDL = NULL;
+ }
+ pIterator->Release();
+ }
+
+ if (!pDL) {
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+ }
+ // detect the capabilities
+ if (pDL->QueryInterface(IID_IDeckLinkAttributes, (void**)&pAttributes) == S_OK) {
+ if (pAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &flag) == S_OK && flag) {
+ self->mKeyingSupported = true;
+ if (pAttributes->GetFlag(BMDDeckLinkSupportsHDKeying, &flag) == S_OK && flag) {
+ self->mHDKeyingSupported = true;
+ }
+ }
+ pAttributes->Release();
+ }
+
+ if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&self->mDLOutput) != S_OK) {
+ self->mDLOutput = NULL;
+ }
+ if (self->mKeyingSupported) {
+ pDL->QueryInterface(IID_IDeckLinkKeyer, (void **)&self->mKeyer);
+ }
+ // we don't need the device anymore, release to avoid leaking
+ pDL->Release();
+
+ if (!self->mDLOutput)
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+
+ if (self->mDLOutput->GetDisplayModeIterator(&pDisplayModeIterator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ displayFlags = (self->mUse3D) ? bmdDisplayModeSupports3D : 0;
+ outputFlags = (self->mUse3D) ? bmdVideoOutputDualStream3D : bmdVideoOutputFlagDefault;
+ pDisplayMode = NULL;
+ i = 0;
+ while (pDisplayModeIterator->Next(&pDisplayMode) == S_OK) {
+ if (pDisplayMode->GetDisplayMode() == self->mDisplayMode
+ && (pDisplayMode->GetFlags() & displayFlags) == displayFlags) {
+ if (self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitBGRA, outputFlags, &support, NULL) != S_OK ||
+ support == bmdDisplayModeNotSupported)
+ {
+ printf("Warning: DeckLink card %d reports no BGRA support, proceed anyway\n", cardIdx);
+ }
+ break;
+ }
+ pDisplayMode->Release();
+ pDisplayMode = NULL;
+ i++;
+ }
+ pDisplayModeIterator->Release();
+
+ if (!pDisplayMode)
+ THRWEXCP(DeckLinkBadFormat, S_OK);
+ self->mSize[0] = pDisplayMode->GetWidth();
+ self->mSize[1] = pDisplayMode->GetHeight();
+ self->mFrameSize = 4*self->mSize[0]*self->mSize[1];
+ pDisplayMode->Release();
+ if (self->mDLOutput->EnableVideoOutput(self->mDisplayMode, outputFlags) != S_OK)
+ // this shouldn't fail
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+
+ if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mLeftFrame) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+ // clear alpha channel in the frame buffer
+ self->mLeftFrame->GetBytes((void **)&bytes);
+ memset(bytes, 0, self->mFrameSize);
+ if (self->mUse3D) {
+ if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mRightFrame) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+ // clear alpha channel in the frame buffer
+ self->mRightFrame->GetBytes((void **)&bytes);
+ memset(bytes, 0, self->mFrameSize);
+ }
+ }
+ catch (Exception & exp)
+ {
+ printf("DeckLink: exception when opening card %d: %s\n", cardIdx, exp.what());
+ exp.report();
+ // normally, the object should be deallocated
+ return -1;
+ }
+ // initialization succeeded
+ return 0;
+}
+
+
+// close added decklink
+PyObject *DeckLink_close(DeckLink * self)
+{
+ if (self->mLeftFrame)
+ self->mLeftFrame->Release();
+ if (self->mRightFrame)
+ self->mRightFrame->Release();
+ if (self->mKeyer)
+ self->mKeyer->Release();
+ if (self->mDLOutput)
+ self->mDLOutput->Release();
+ decklink_Reset(self);
+ Py_RETURN_NONE;
+}
+
+
+// refresh decklink key frame
+static PyObject *DeckLink_refresh(DeckLink *self, PyObject *args)
+{
+ // get parameter - refresh source
+ PyObject *param;
+ double ts = -1.0;
+
+ if (!PyArg_ParseTuple(args, "O|d:refresh", &param, &ts) || !PyBool_Check(param)) {
+ // report error
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return NULL;
+ }
+ // some trick here: we are in the business of loading a key frame in decklink,
+ // no use to do it if we are still in the same rendering frame.
+ // We find this out by looking at the engine current clock time
+ KX_KetsjiEngine* engine = KX_GetActiveEngine();
+ if (engine->GetClockTime() != self->m_lastClock)
+ {
+ self->m_lastClock = engine->GetClockTime();
+ // set source refresh
+ bool refreshSource = (param == Py_True);
+ uint32_t *leftEye = NULL;
+ uint32_t *rightEye = NULL;
+ // try to process key frame from source
+ try {
+ // check if optimization is possible
+ if (self->m_leftEye != NULL) {
+ ImageBase *leftImage = self->m_leftEye->m_image;
+ short * srcSize = leftImage->getSize();
+ self->mLeftFrame->GetBytes((void **)&leftEye);
+ if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1])
+ {
+ // buffer has same size, can load directly
+ if (!leftImage->loadImage(leftEye, self->mFrameSize, GL_BGRA, ts))
+ leftEye = NULL;
+ }
+ else {
+ // scaling is required, go the hard way
+ unsigned int *src = leftImage->getImage(0, ts);
+ if (src != NULL)
+ decklink_ConvImage(leftEye, self->mSize, src, srcSize, self->mUseExtend);
+ else
+ leftEye = NULL;
+ }
+ }
+ if (leftEye) {
+ if (self->mUse3D && self->m_rightEye != NULL) {
+ ImageBase *rightImage = self->m_rightEye->m_image;
+ short * srcSize = rightImage->getSize();
+ self->mRightFrame->GetBytes((void **)&rightEye);
+ if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1])
+ {
+ // buffer has same size, can load directly
+ rightImage->loadImage(rightEye, self->mFrameSize, GL_BGRA, ts);
+ }
+ else {
+ // scaling is required, go the hard way
+ unsigned int *src = rightImage->getImage(0, ts);
+ if (src != NULL)
+ decklink_ConvImage(rightEye, self->mSize, src, srcSize, self->mUseExtend);
+ }
+ }
+ if (self->mUse3D) {
+ DeckLink3DFrameWrapper frame3D(
+ (IDeckLinkVideoFrame*)self->mLeftFrame,
+ (IDeckLinkVideoFrame*)self->mRightFrame);
+ self->mDLOutput->DisplayVideoFrameSync(&frame3D);
+ }
+ else {
+ self->mDLOutput->DisplayVideoFrameSync((IDeckLinkVideoFrame*)self->mLeftFrame);
+ }
+ }
+ // refresh texture source, if required
+ if (refreshSource) {
+ if (self->m_leftEye)
+ self->m_leftEye->m_image->refresh();
+ if (self->m_rightEye)
+ self->m_rightEye->m_image->refresh();
+ }
+ }
+ CATCH_EXCP;
+ }
+ Py_RETURN_NONE;
+}
+
+// get source object
+static PyObject *DeckLink_getSource(DeckLink *self, PyObject *value, void *closure)
+{
+ // if source exists
+ if (self->m_leftEye != NULL) {
+ Py_INCREF(self->m_leftEye);
+ return reinterpret_cast<PyObject*>(self->m_leftEye);
+ }
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// set source object
+int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure)
+{
+ // check new value
+ if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // increase ref count for new value
+ Py_INCREF(value);
+ // release previous
+ Py_XDECREF(self->m_leftEye);
+ // set new value
+ self->m_leftEye = reinterpret_cast<PyImage*>(value);
+ // return success
+ return 0;
+}
+
+// get source object
+static PyObject *DeckLink_getRight(DeckLink *self, PyObject *value, void *closure)
+{
+ // if source exists
+ if (self->m_rightEye != NULL)
+ {
+ Py_INCREF(self->m_rightEye);
+ return reinterpret_cast<PyObject*>(self->m_rightEye);
+ }
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// set source object
+static int DeckLink_setRight(DeckLink *self, PyObject *value, void *closure)
+{
+ // check new value
+ if (value == NULL || !pyImageTypes.in(Py_TYPE(value)))
+ {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // increase ref count for new value
+ Py_INCREF(value);
+ // release previous
+ Py_XDECREF(self->m_rightEye);
+ // set new value
+ self->m_rightEye = reinterpret_cast<PyImage*>(value);
+ // return success
+ return 0;
+}
+
+
+static PyObject *DeckLink_getKeying(DeckLink *self, PyObject *value, void *closure)
+{
+ if (self->mUseKeying) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+static int DeckLink_setKeying(DeckLink *self, PyObject *value, void *closure)
+{
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ if (self->mKeyer != NULL)
+ {
+ if (value == Py_True)
+ {
+ if (self->mKeyer->Enable(false) != S_OK)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Error enabling keyer");
+ return -1;
+ }
+ self->mUseKeying = true;
+ self->mKeyer->SetLevel(self->mKeyingLevel);
+ }
+ else
+ {
+ self->mKeyer->Disable();
+ self->mUseKeying = false;
+ }
+ }
+ // success
+ return 0;
+}
+
+static PyObject *DeckLink_getLevel(DeckLink *self, PyObject *value, void *closure)
+{
+ return Py_BuildValue("h", self->mKeyingLevel);
+}
+
+static int DeckLink_setLevel(DeckLink *self, PyObject *value, void *closure)
+{
+ long level;
+ if (value == NULL || !PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "The value must be an integer from 0 to 255");
+ return -1;
+ }
+ level = PyLong_AsLong(value);
+ if (level > 255)
+ level = 255;
+ else if (level < 0)
+ level = 0;
+ self->mKeyingLevel = (uint8_t)level;
+ if (self->mUseKeying) {
+ if (self->mKeyer->SetLevel(self->mKeyingLevel) != S_OK) {
+ PyErr_SetString(PyExc_RuntimeError, "Error changin level of keyer");
+ return -1;
+ }
+ }
+ // success
+ return 0;
+}
+
+static PyObject *DeckLink_getExtend(DeckLink *self, PyObject *value, void *closure)
+{
+ if (self->mUseExtend) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+static int DeckLink_setExtend(DeckLink *self, PyObject *value, void *closure)
+{
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ self->mUseExtend = (value == Py_True);
+ return 0;
+}
+
+// class DeckLink methods
+static PyMethodDef decklinkMethods[] =
+{
+ { "close", (PyCFunction)DeckLink_close, METH_NOARGS, "Close dynamic decklink and restore original"},
+ { "refresh", (PyCFunction)DeckLink_refresh, METH_VARARGS, "Refresh decklink from source"},
+ {NULL} /* Sentinel */
+};
+
+// class DeckLink attributes
+static PyGetSetDef decklinkGetSets[] =
+{
+ { (char*)"source", (getter)DeckLink_getSource, (setter)DeckLink_setSource, (char*)"source of decklink (left eye)", NULL},
+ { (char*)"right", (getter)DeckLink_getRight, (setter)DeckLink_setRight, (char*)"source of decklink (right eye)", NULL },
+ { (char*)"keying", (getter)DeckLink_getKeying, (setter)DeckLink_setKeying, (char*)"whether keying is enabled (frame is alpha-composited with passthrough output)", NULL },
+ { (char*)"level", (getter)DeckLink_getLevel, (setter)DeckLink_setLevel, (char*)"change the level of keying (overall alpha level of key frame, 0 to 255)", NULL },
+ { (char*)"extend", (getter)DeckLink_getExtend, (setter)DeckLink_setExtend, (char*)"whether image should stretched to fit frame", NULL },
+ { NULL }
+};
+
+
+// class DeckLink declaration
+PyTypeObject DeckLinkType =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VideoTexture.DeckLink", /*tp_name*/
+ sizeof(DeckLink), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)DeckLink_dealloc,/*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &imageBufferProcs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "DeckLink objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ decklinkMethods, /* tp_methods */
+ 0, /* tp_members */
+ decklinkGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)DeckLink_init, /* tp_init */
+ 0, /* tp_alloc */
+ DeckLink_new, /* tp_new */
+};
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h
new file mode 100644
index 00000000000..4528fe7cec0
--- /dev/null
+++ b/source/gameengine/VideoTexture/DeckLink.h
@@ -0,0 +1,86 @@
+/*
+ * ***** 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 VideoTexture/DeckLink.h
+ * \ingroup bgevideotex
+ */
+
+#ifndef __DECKLINK_H__
+#define __DECKLINK_H__
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+#include "EXP_PyObjectPlus.h"
+#include <structmember.h>
+
+#include "DNA_image_types.h"
+
+#include "DeckLinkAPI.h"
+
+#include "ImageBase.h"
+#include "BlendType.h"
+#include "Exception.h"
+
+
+// type DeckLink declaration
+struct DeckLink
+{
+ PyObject_HEAD
+
+ // last refresh
+ double m_lastClock;
+ // decklink card to which we output
+ IDeckLinkOutput * mDLOutput;
+ IDeckLinkKeyer * mKeyer;
+ IDeckLinkMutableVideoFrame *mLeftFrame;
+ IDeckLinkMutableVideoFrame *mRightFrame;
+ bool mUse3D;
+ bool mUseKeying;
+ bool mUseExtend;
+ bool mKeyingSupported;
+ bool mHDKeyingSupported;
+ uint8_t mKeyingLevel;
+ BMDDisplayMode mDisplayMode;
+ short mSize[2];
+ uint32_t mFrameSize;
+
+ // image source
+ PyImage * m_leftEye;
+ PyImage * m_rightEye;
+};
+
+
+// DeckLink type description
+extern PyTypeObject DeckLinkType;
+
+// helper function
+HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode);
+HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *displayMode);
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
+
+#endif /* __DECKLINK_H__ */
diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp
index 08616e0c41c..9f82987ea62 100644
--- a/source/gameengine/VideoTexture/Exception.cpp
+++ b/source/gameengine/VideoTexture/Exception.cpp
@@ -213,6 +213,7 @@ void registerAllExceptions(void)
ImageSizesNotMatchDesc.registerDesc();
ImageHasExportsDesc.registerDesc();
InvalidColorChannelDesc.registerDesc();
+ InvalidImageModeDesc.registerDesc();
SceneInvalidDesc.registerDesc();
CameraInvalidDesc.registerDesc();
ObserverInvalidDesc.registerDesc();
@@ -223,4 +224,18 @@ void registerAllExceptions(void)
MirrorTooSmallDesc.registerDesc();
SourceVideoEmptyDesc.registerDesc();
SourceVideoCreationDesc.registerDesc();
+ OffScreenInvalidDesc.registerDesc();
+#ifdef WITH_GAMEENGINE_DECKLINK
+ AutoDetectionNotAvailDesc.registerDesc();
+ DeckLinkBadDisplayModeDesc.registerDesc();
+ DeckLinkBadPixelFormatDesc.registerDesc();
+ DeckLinkOpenCardDesc.registerDesc();
+ DeckLinkBadFormatDesc.registerDesc();
+ DeckLinkInternalErrorDesc.registerDesc();
+ SourceVideoOnlyCaptureDesc.registerDesc();
+ VideoDeckLinkBadFormatDesc.registerDesc();
+ VideoDeckLinkOpenCardDesc.registerDesc();
+ VideoDeckLinkDvpInternalErrorDesc.registerDesc();
+ VideoDeckLinkPinMemoryErrorDesc.registerDesc();
+#endif
}
diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h
index c3c27abe019..c4de85ff34d 100644
--- a/source/gameengine/VideoTexture/Exception.h
+++ b/source/gameengine/VideoTexture/Exception.h
@@ -46,7 +46,7 @@
throw Exception (err, macroHRslt, __FILE__, __LINE__); \
}
-#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__);
+#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__)
#if defined WIN32
@@ -209,9 +209,11 @@ extern ExpDesc MaterialNotAvailDesc;
extern ExpDesc ImageSizesNotMatchDesc;
extern ExpDesc ImageHasExportsDesc;
extern ExpDesc InvalidColorChannelDesc;
+extern ExpDesc InvalidImageModeDesc;
extern ExpDesc SceneInvalidDesc;
extern ExpDesc CameraInvalidDesc;
extern ExpDesc ObserverInvalidDesc;
+extern ExpDesc OffScreenInvalidDesc;
extern ExpDesc MirrorInvalidDesc;
extern ExpDesc MirrorSizeInvalidDesc;
extern ExpDesc MirrorNormalInvalidDesc;
@@ -219,7 +221,19 @@ extern ExpDesc MirrorHorizontalDesc;
extern ExpDesc MirrorTooSmallDesc;
extern ExpDesc SourceVideoEmptyDesc;
extern ExpDesc SourceVideoCreationDesc;
-
+extern ExpDesc DeckLinkBadDisplayModeDesc;
+extern ExpDesc DeckLinkBadPixelFormatDesc;
+extern ExpDesc AutoDetectionNotAvailDesc;
+extern ExpDesc DeckLinkOpenCardDesc;
+extern ExpDesc DeckLinkBadFormatDesc;
+extern ExpDesc DeckLinkInternalErrorDesc;
+extern ExpDesc SourceVideoOnlyCaptureDesc;
+extern ExpDesc VideoDeckLinkBadFormatDesc;
+extern ExpDesc VideoDeckLinkOpenCardDesc;
+extern ExpDesc VideoDeckLinkDvpInternalErrorDesc;
+extern ExpDesc VideoDeckLinkPinMemoryErrorDesc;
+
+extern ExceptionID InvalidImageMode;
void registerAllExceptions(void);
#endif
diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h
index 498917e2375..db688d551d0 100644
--- a/source/gameengine/VideoTexture/FilterBase.h
+++ b/source/gameengine/VideoTexture/FilterBase.h
@@ -44,6 +44,13 @@
#define VT_A(v) ((unsigned char*)&v)[3]
#define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a
+#ifdef __BIG_ENDIAN__
+# define VT_SWAPBR(i) ((((i) >> 16) & 0xFF00) + (((i) & 0xFF00) << 16) + ((i) & 0xFF00FF))
+#else
+# define VT_SWAPBR(i) ((((i) & 0xFF) << 16) + (((i) >> 16) & 0xFF) + ((i) & 0xFF00FF00))
+#endif
+
+
// forward declaration
class FilterBase;
diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h
index bc80b2b36cc..820576dfff9 100644
--- a/source/gameengine/VideoTexture/FilterSource.h
+++ b/source/gameengine/VideoTexture/FilterSource.h
@@ -81,6 +81,30 @@ protected:
}
};
+/// class for BGRA32 conversion
+class FilterBGRA32 : public FilterBase
+{
+public:
+ /// constructor
+ FilterBGRA32 (void) {}
+ /// destructor
+ virtual ~FilterBGRA32 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 4; }
+
+protected:
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter(
+ unsigned char *src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ VT_RGBA(val,src[2],src[1],src[0],src[3]);
+ return val;
+ }
+};
+
+
/// class for BGR24 conversion
class FilterBGR24 : public FilterBase
{
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 8be152c7b8e..0db1fa293da 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -32,7 +32,6 @@
extern "C" {
#include "bgl.h"
}
-#include "glew-mx.h"
#include <vector>
#include <string.h>
@@ -50,6 +49,14 @@ extern "C" {
// ImageBase class implementation
+ExceptionID ImageHasExports;
+ExceptionID InvalidColorChannel;
+ExceptionID InvalidImageMode;
+
+ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize");
+ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1");
+ExpDesc InvalidImageModeDesc(InvalidImageMode, "Invalid image mode, only RGBA and BGRA are supported");
+
// constructor
ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0),
m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false),
@@ -111,6 +118,28 @@ unsigned int * ImageBase::getImage (unsigned int texId, double ts)
return m_avail ? m_image : NULL;
}
+bool ImageBase::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
+{
+ unsigned int *d, *s, v, len;
+ if (getImage(0, ts) != NULL && size >= getBuffSize()) {
+ switch (format) {
+ case GL_RGBA:
+ memcpy(buffer, m_image, getBuffSize());
+ break;
+ case GL_BGRA:
+ len = (unsigned int)m_size[0] * m_size[1];
+ for (s=m_image, d=buffer; len; len--) {
+ v = *s++;
+ *d++ = VT_SWAPBR(v);
+ }
+ break;
+ default:
+ THRWEXCP(InvalidImageMode,S_OK);
+ }
+ return true;
+ }
+ return false;
+}
// refresh image source
void ImageBase::refresh (void)
@@ -179,11 +208,18 @@ void ImageBase::setFilter (PyFilter * filt)
m_pyfilter = filt;
}
-ExceptionID ImageHasExports;
-ExceptionID InvalidColorChannel;
+void ImageBase::swapImageBR()
+{
+ unsigned int size, v, *s;
-ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize");
-ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1");
+ if (m_avail) {
+ size = 1 * m_size[0] * m_size[1];
+ for (s=m_image; size; size--) {
+ v = *s;
+ *s++ = VT_SWAPBR(v);
+ }
+ }
+}
// initialize image data
void ImageBase::init (short width, short height)
@@ -500,10 +536,57 @@ PyObject *Image_getSize (PyImage *self, void *closure)
}
// refresh image
-PyObject *Image_refresh (PyImage *self)
-{
+PyObject *Image_refresh (PyImage *self, PyObject *args)
+{
+ Py_buffer buffer;
+ bool done = true;
+ char *mode = NULL;
+ double ts = -1.0;
+ unsigned int format;
+
+ memset(&buffer, 0, sizeof(buffer));
+ if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) {
+ if (buffer.buf) {
+ // a target buffer is provided, verify its format
+ if (buffer.readonly) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable");
+ }
+ else if (!PyBuffer_IsContiguous(&buffer, 'C')) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory");
+ }
+ else if (((intptr_t)buffer.buf & 3) != 0) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary");
+ }
+ else {
+ // ready to get the image into our buffer
+ try {
+ if (mode == NULL || !strcmp(mode, "RGBA"))
+ format = GL_RGBA;
+ else if (!strcmp(mode, "BGRA"))
+ format = GL_BGRA;
+ else
+ THRWEXCP(InvalidImageMode,S_OK);
+
+ done = self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts);
+ }
+ catch (Exception & exp) {
+ exp.report();
+ }
+ }
+ PyBuffer_Release(&buffer);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ }
+ }
+ else {
+ return NULL;
+ }
+
self->m_image->refresh();
- Py_RETURN_NONE;
+ if (done)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
}
// get scale
diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h
index f646d145365..4c9fc5a58fb 100644
--- a/source/gameengine/VideoTexture/ImageBase.h
+++ b/source/gameengine/VideoTexture/ImageBase.h
@@ -40,6 +40,7 @@
#include "FilterBase.h"
+#include "glew-mx.h"
// forward declarations
struct PyImage;
@@ -104,6 +105,13 @@ public:
/// calculate size(nearest power of 2)
static short calcSize(short size);
+ /// calculate image from sources and send it to a target buffer instead of a texture
+ /// format is GL_RGBA or GL_BGRA
+ virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts);
+
+ /// swap the B and R channel in-place in the image buffer
+ void swapImageBR();
+
/// number of buffer pointing to m_image, public because not handled by this class
int m_exports;
@@ -348,7 +356,7 @@ PyObject *Image_getImage(PyImage *self, char *mode);
// get image size
PyObject *Image_getSize(PyImage *self, void *closure);
// refresh image - invalidate current content
-PyObject *Image_refresh(PyImage *self);
+PyObject *Image_refresh(PyImage *self, PyObject *args);
// get scale
PyObject *Image_getScale(PyImage *self, void *closure);
diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp
index 973be52e0fc..2de00f5ba05 100644
--- a/source/gameengine/VideoTexture/ImageMix.cpp
+++ b/source/gameengine/VideoTexture/ImageMix.cpp
@@ -156,7 +156,7 @@ static PyMethodDef imageMixMethods[] = {
{"getWeight", (PyCFunction)getWeight, METH_VARARGS, "get image source weight"},
{"setWeight", (PyCFunction)setWeight, METH_VARARGS, "set image source weight"},
// methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"},
{NULL}
};
// attributes structure
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index a374fbba2df..9991bf42a9f 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -43,6 +43,8 @@
#include "RAS_CameraData.h"
#include "RAS_MeshObject.h"
#include "RAS_Polygon.h"
+#include "RAS_IOffScreen.h"
+#include "RAS_ISync.h"
#include "BLI_math.h"
#include "ImageRender.h"
@@ -51,11 +53,12 @@
#include "Exception.h"
#include "Texture.h"
-ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid;
+ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid, OffScreenInvalid;
ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall;
ExpDesc SceneInvalidDesc(SceneInvalid, "Scene object is invalid");
ExpDesc CameraInvalidDesc(CameraInvalid, "Camera object is invalid");
ExpDesc ObserverInvalidDesc(ObserverInvalid, "Observer object is invalid");
+ExpDesc OffScreenInvalidDesc(OffScreenInvalid, "Offscreen object is invalid");
ExpDesc MirrorInvalidDesc(MirrorInvalid, "Mirror object is invalid");
ExpDesc MirrorSizeInvalidDesc(MirrorSizeInvalid, "Mirror has no vertex or no size");
ExpDesc MirrorNormalInvalidDesc(MirrorNormalInvalid, "Cannot determine mirror plane");
@@ -63,12 +66,15 @@ ExpDesc MirrorHorizontalDesc(MirrorHorizontal, "Mirror is horizontal in local sp
ExpDesc MirrorTooSmallDesc(MirrorTooSmall, "Mirror is too small");
// constructor
-ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
- ImageViewport(),
+ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera, PyRASOffScreen * offscreen) :
+ ImageViewport(offscreen),
m_render(true),
+ m_done(false),
m_scene(scene),
m_camera(camera),
m_owncamera(false),
+ m_offscreen(offscreen),
+ m_sync(NULL),
m_observer(NULL),
m_mirror(NULL),
m_clip(100.f),
@@ -81,6 +87,10 @@ ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
m_engine = KX_GetActiveEngine();
m_rasterizer = m_engine->GetRasterizer();
m_canvas = m_engine->GetCanvas();
+ // keep a reference to the offscreen buffer
+ if (m_offscreen) {
+ Py_INCREF(m_offscreen);
+ }
}
// destructor
@@ -88,6 +98,9 @@ ImageRender::~ImageRender (void)
{
if (m_owncamera)
m_camera->Release();
+ if (m_sync)
+ delete m_sync;
+ Py_XDECREF(m_offscreen);
}
// get background color
@@ -121,30 +134,41 @@ void ImageRender::setBackgroundFromScene (KX_Scene *scene)
// capture image from viewport
-void ImageRender::calcImage (unsigned int texId, double ts)
+void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int format)
{
- if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture
- m_camera->GetViewport() || // camera must be inactive
- m_camera == m_scene->GetActiveCamera())
- {
- // no need to compute texture in non texture rendering
- m_avail = false;
- return;
- }
// render the scene from the camera
- Render();
- // get image from viewport
- ImageViewport::calcImage(texId, ts);
- // restore OpenGL state
- m_canvas->EndFrame();
+ if (!m_done) {
+ if (!Render()) {
+ return;
+ }
+ }
+ else if (m_offscreen) {
+ m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ);
+ }
+ // wait until all render operations are completed
+ WaitSync();
+ // get image from viewport (or FBO)
+ ImageViewport::calcViewport(texId, ts, format);
+ if (m_offscreen) {
+ m_offscreen->ofs->Unbind();
+ }
}
-void ImageRender::Render()
+bool ImageRender::Render()
{
RAS_FrameFrustum frustum;
- if (!m_render)
- return;
+ if (!m_render ||
+ m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture
+ m_camera->GetViewport() || // camera must be inactive
+ m_camera == m_scene->GetActiveCamera())
+ {
+ // no need to compute texture in non texture rendering
+ return false;
+ }
+
+ if (!m_scene->IsShadowDone())
+ m_engine->RenderShadowBuffers(m_scene);
if (m_mirror)
{
@@ -164,7 +188,7 @@ void ImageRender::Render()
MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
// if distance < 0.01 => observer is on wrong side of mirror, don't render
if (observerDistance < 0.01)
- return;
+ return false;
// set camera world position = observerPos + normal * 2 * distance
MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
@@ -215,7 +239,15 @@ void ImageRender::Render()
RAS_Rect area = m_canvas->GetWindowArea();
// The screen area that ImageViewport will copy is also the rendering zone
- m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
+ if (m_offscreen) {
+ // bind the fbo and set the viewport to full size
+ m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER);
+ // this is needed to stop crashing in canvas check
+ m_canvas->UpdateViewPort(0, 0, m_offscreen->ofs->GetWidth(), m_offscreen->ofs->GetHeight());
+ }
+ else {
+ m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
+ }
m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
m_rasterizer->BeginFrame(m_engine->GetClockTime());
@@ -292,17 +324,18 @@ void ImageRender::Render()
MT_Transform camtrans(m_camera->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->NodeGetLocalScaling(), m_camera->GetCameraData()->m_perspective);
m_camera->SetModelviewMatrix(viewmat);
// restore the stereo mode now that the matrix is computed
m_rasterizer->SetStereoMode(stereomode);
- if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) {
- // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer
- // but we need to draw on the left buffer to capture the render
- // TODO: implement an explicit function in rasterizer to restore the left buffer.
- m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
- }
+ if (m_rasterizer->Stereo()) {
+ // stereo mode change render settings that disturb this render, cancel them all
+ // we don't need to restore them as they are set before each frame render.
+ glDrawBuffer(GL_BACK_LEFT);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
@@ -314,8 +347,48 @@ void ImageRender::Render()
// restore the canvas area now that the render is completed
m_canvas->GetWindowArea() = area;
+ m_canvas->EndFrame();
+
+ // In case multisample is active, blit the FBO
+ if (m_offscreen)
+ m_offscreen->ofs->Blit();
+ // end of all render operations, let's create a sync object just in case
+ if (m_sync) {
+ // a sync from a previous render, should not happen
+ delete m_sync;
+ m_sync = NULL;
+ }
+ m_sync = m_rasterizer->CreateSync(RAS_ISync::RAS_SYNC_TYPE_FENCE);
+ // remember that we have done render
+ m_done = true;
+ // the image is not available at this stage
+ m_avail = false;
+ return true;
+}
+
+void ImageRender::Unbind()
+{
+ if (m_offscreen)
+ {
+ m_offscreen->ofs->Unbind();
+ }
}
+void ImageRender::WaitSync()
+{
+ if (m_sync) {
+ m_sync->Wait();
+ // done with it, deleted it
+ delete m_sync;
+ m_sync = NULL;
+ }
+ if (m_offscreen) {
+ // this is needed to finalize the image if the target is a texture
+ m_offscreen->ofs->MipMap();
+ }
+ // all rendered operation done and complete, invalidate render for next time
+ m_done = false;
+}
// cast Image pointer to ImageRender
inline ImageRender * getImageRender (PyImage *self)
@@ -337,11 +410,13 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
PyObject *scene;
// camera object
PyObject *camera;
+ // offscreen buffer object
+ PyRASOffScreen *offscreen = NULL;
// parameter keywords
- static const char *kwlist[] = {"sceneObj", "cameraObj", NULL};
+ static const char *kwlist[] = {"sceneObj", "cameraObj", "ofsObj", NULL};
// get parameters
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO",
- const_cast<char**>(kwlist), &scene, &camera))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O",
+ const_cast<char**>(kwlist), &scene, &camera, &offscreen))
return -1;
try
{
@@ -357,11 +432,16 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
// throw exception if camera is not available
if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK);
+ if (offscreen) {
+ if (Py_TYPE(offscreen) != &PyRASOffScreen_Type) {
+ THRWEXCP(OffScreenInvalid, S_OK);
+ }
+ }
// get pointer to image structure
PyImage *self = reinterpret_cast<PyImage*>(pySelf);
// create source object
if (self->m_image != NULL) delete self->m_image;
- self->m_image = new ImageRender(scenePtr, cameraPtr);
+ self->m_image = new ImageRender(scenePtr, cameraPtr, offscreen);
}
catch (Exception & exp)
{
@@ -372,6 +452,55 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
return 0;
}
+static PyObject *ImageRender_refresh(PyImage *self, PyObject *args)
+{
+ ImageRender *imageRender = getImageRender(self);
+
+ if (!imageRender) {
+ PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object");
+ return NULL;
+ }
+ if (PyArg_ParseTuple(args, "")) {
+ // refresh called with no argument.
+ // For other image objects it simply invalidates the image buffer
+ // For ImageRender it triggers a render+sync
+ // Note that this only makes sense when doing offscreen render on texture
+ if (!imageRender->isDone()) {
+ if (!imageRender->Render()) {
+ Py_RETURN_FALSE;
+ }
+ // as we are not trying to read the pixels, just unbind
+ imageRender->Unbind();
+ }
+ // wait until all render operations are completed
+ // this will also finalize the texture
+ imageRender->WaitSync();
+ Py_RETURN_TRUE;
+ }
+ else {
+ // fallback on standard processing
+ PyErr_Clear();
+ return Image_refresh(self, args);
+ }
+}
+
+// refresh image
+static PyObject *ImageRender_render(PyImage *self)
+{
+ ImageRender *imageRender = getImageRender(self);
+
+ if (!imageRender) {
+ PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object");
+ return NULL;
+ }
+ if (!imageRender->Render()) {
+ Py_RETURN_FALSE;
+ }
+ // we are not reading the pixels now, unbind
+ imageRender->Unbind();
+ Py_RETURN_TRUE;
+}
+
// get background color
static PyObject *getBackground (PyImage *self, void *closure)
@@ -410,7 +539,8 @@ static int setBackground(PyImage *self, PyObject *value, void *closure)
// methods structure
static PyMethodDef imageRenderMethods[] =
{ // methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)ImageRender_refresh, METH_VARARGS, "Refresh image - invalidate its current content after optionally transferring its content to a target buffer"},
+ {"render", (PyCFunction)ImageRender_render, METH_NOARGS, "Render scene - run before refresh() to performs asynchronous render"},
{NULL}
};
// attributes structure
@@ -601,7 +731,9 @@ static PyGetSetDef imageMirrorGetSets[] =
ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial *mat) :
ImageViewport(),
m_render(false),
+ m_done(false),
m_scene(scene),
+ m_offscreen(NULL),
m_observer(observer),
m_mirror(mirror),
m_clip(100.f)
diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h
index ef55e4dea84..d062db44348 100644
--- a/source/gameengine/VideoTexture/ImageRender.h
+++ b/source/gameengine/VideoTexture/ImageRender.h
@@ -39,6 +39,8 @@
#include "DNA_screen_types.h"
#include "RAS_ICanvas.h"
#include "RAS_IRasterizer.h"
+#include "RAS_IOffScreen.h"
+#include "RAS_ISync.h"
#include "ImageViewport.h"
@@ -48,7 +50,7 @@ class ImageRender : public ImageViewport
{
public:
/// constructor
- ImageRender(KX_Scene *scene, KX_Camera *camera);
+ ImageRender(KX_Scene *scene, KX_Camera *camera, PyRASOffScreen *offscreen);
ImageRender(KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial * mat);
/// destructor
@@ -63,16 +65,30 @@ public:
float getClip (void) { return m_clip; }
/// set whole buffer use
void setClip (float clip) { m_clip = clip; }
+ /// render status
+ bool isDone() { return m_done; }
+ /// render frame (public so that it is accessible from python)
+ bool Render();
+ /// in case fbo is used, method to unbind
+ void Unbind();
+ /// wait for render to complete
+ void WaitSync();
protected:
/// true if ready to render
bool m_render;
+ /// is render done already?
+ bool m_done;
/// rendered scene
KX_Scene * m_scene;
/// camera for render
KX_Camera * m_camera;
/// do we own the camera?
bool m_owncamera;
+ /// if offscreen render
+ PyRASOffScreen *m_offscreen;
+ /// object to synchronize render even if no buffer transfer
+ RAS_ISync *m_sync;
/// for mirror operation
KX_GameObject * m_observer;
KX_GameObject * m_mirror;
@@ -91,15 +107,15 @@ protected:
KX_KetsjiEngine* m_engine;
/// background color
- float m_background[4];
+ float m_background[4];
/// render 3d scene to image
- virtual void calcImage (unsigned int texId, double ts);
+ virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
+
+ /// render 3d scene to image
+ virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
- void Render();
- void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
- void RenderFrame(KX_Scene* scene, KX_Camera* cam);
void setBackgroundFromScene(KX_Scene *scene);
void SetWorldSettings(KX_WorldInfo* wi);
};
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
index 820a019832e..8852c190053 100644
--- a/source/gameengine/VideoTexture/ImageViewport.cpp
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -45,14 +45,22 @@
// constructor
-ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
+ImageViewport::ImageViewport (PyRASOffScreen *offscreen) : m_alpha(false), m_texInit(false)
{
// get viewport rectangle
- RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea();
- m_viewport[0] = rect.GetLeft();
- m_viewport[1] = rect.GetBottom();
- m_viewport[2] = rect.GetWidth();
- m_viewport[3] = rect.GetHeight();
+ if (offscreen) {
+ m_viewport[0] = 0;
+ m_viewport[1] = 0;
+ m_viewport[2] = offscreen->ofs->GetWidth();
+ m_viewport[3] = offscreen->ofs->GetHeight();
+ }
+ else {
+ RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea();
+ m_viewport[0] = rect.GetLeft();
+ m_viewport[1] = rect.GetBottom();
+ m_viewport[2] = rect.GetWidth();
+ m_viewport[3] = rect.GetHeight();
+ }
//glGetIntegerv(GL_VIEWPORT, m_viewport);
// create buffer for viewport image
@@ -60,7 +68,7 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
// float (1 float = 4 bytes per pixel)
m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]];
// set attributes
- setWhole(false);
+ setWhole((offscreen) ? true : false);
}
// destructor
@@ -126,25 +134,26 @@ void ImageViewport::setPosition (GLint pos[2])
// capture image from viewport
-void ImageViewport::calcImage (unsigned int texId, double ts)
+void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int format)
{
// if scale was changed
if (m_scaleChange)
// reset image
init(m_capSize[0], m_capSize[1]);
// if texture wasn't initialized
- if (!m_texInit) {
+ if (!m_texInit && texId != 0) {
// initialize it
loadTexture(texId, m_image, m_size);
m_texInit = true;
}
// if texture can be directly created
- if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
- && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth)
+ if (texId != 0 && m_pyfilter == NULL && m_size[0] == m_capSize[0] &&
+ m_size[1] == m_capSize[1] && !m_flip && !m_zbuff && !m_depth)
{
// just copy current viewport to texture
glBindTexture(GL_TEXTURE_2D, texId);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]);
+ glBindTexture(GL_TEXTURE_2D, 0);
// image is not available
m_avail = false;
}
@@ -176,11 +185,33 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
// get frame buffer data
if (m_alpha) {
- glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
- GL_UNSIGNED_BYTE, m_viewportImage);
- // filter loaded data
- FilterRGBA32 filt;
- filterImage(filt, m_viewportImage, m_capSize);
+ // as we are reading the pixel in the native format, we can read directly in the image buffer
+ // if we are sure that no processing is needed on the image
+ if (m_size[0] == m_capSize[0] &&
+ m_size[1] == m_capSize[1] &&
+ !m_flip &&
+ !m_pyfilter)
+ {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
+ GL_UNSIGNED_BYTE, m_image);
+ m_avail = true;
+ }
+ else if (!m_pyfilter) {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
+ GL_UNSIGNED_BYTE, m_viewportImage);
+ FilterRGBA32 filt;
+ filterImage(filt, m_viewportImage, m_capSize);
+ }
+ else {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
+ GL_UNSIGNED_BYTE, m_viewportImage);
+ FilterRGBA32 filt;
+ filterImage(filt, m_viewportImage, m_capSize);
+ if (format == GL_BGRA) {
+ // in place byte swapping
+ swapImageBR();
+ }
+ }
}
else {
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB,
@@ -188,12 +219,46 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
// filter loaded data
FilterRGB24 filt;
filterImage(filt, m_viewportImage, m_capSize);
+ if (format == GL_BGRA) {
+ // in place byte swapping
+ swapImageBR();
+ }
}
}
}
}
}
+bool ImageViewport::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
+{
+ unsigned int *tmp_image;
+ bool ret;
+
+ // if scale was changed
+ if (m_scaleChange) {
+ // reset image
+ init(m_capSize[0], m_capSize[1]);
+ }
+
+ // size must be identical
+ if (size < getBuffSize())
+ return false;
+
+ if (m_avail) {
+ // just copy
+ return ImageBase::loadImage(buffer, size, format, ts);
+ }
+ else {
+ tmp_image = m_image;
+ m_image = buffer;
+ calcViewport(0, ts, format);
+ ret = m_avail;
+ m_image = tmp_image;
+ // since the image was not loaded to our buffer, it's not valid
+ m_avail = false;
+ }
+ return ret;
+}
// cast Image pointer to ImageViewport
@@ -336,7 +401,7 @@ int ImageViewport_setCaptureSize(PyImage *self, PyObject *value, void *closure)
// methods structure
static PyMethodDef imageViewportMethods[] =
{ // methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"},
{NULL}
};
// attributes structure
diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h
index 10d894a9fb8..8a7e9cfd2ba 100644
--- a/source/gameengine/VideoTexture/ImageViewport.h
+++ b/source/gameengine/VideoTexture/ImageViewport.h
@@ -35,6 +35,7 @@
#include "Common.h"
#include "ImageBase.h"
+#include "RAS_IOffScreen.h"
/// class for viewport access
@@ -42,7 +43,7 @@ class ImageViewport : public ImageBase
{
public:
/// constructor
- ImageViewport (void);
+ ImageViewport (PyRASOffScreen *offscreen=NULL);
/// destructor
virtual ~ImageViewport (void);
@@ -67,6 +68,9 @@ public:
/// set position in viewport
void setPosition (GLint pos[2] = NULL);
+ /// capture image from viewport to user buffer
+ virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts);
+
protected:
/// frame buffer rectangle
GLint m_viewport[4];
@@ -89,7 +93,10 @@ protected:
bool m_texInit;
/// capture image from viewport
- virtual void calcImage (unsigned int texId, double ts);
+ virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
+
+ /// capture image from viewport
+ virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
/// get viewport size
GLint * getViewportSize (void) { return m_viewport + 2; }
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index f1c7bc303ee..bb995747360 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -393,9 +393,10 @@ static PyObject *Texture_refresh(Texture *self, PyObject *args)
}
// load texture for rendering
loadTexture(self->m_actTex, texture, size, self->m_mipmap);
-
- // refresh texture source, if required
- if (refreshSource) self->m_source->m_image->refresh();
+ }
+ // refresh texture source, if required
+ if (refreshSource) {
+ self->m_source->m_image->refresh();
}
}
}
diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp
index 9c8df0ca8c4..d373055b5df 100644
--- a/source/gameengine/VideoTexture/VideoBase.cpp
+++ b/source/gameengine/VideoTexture/VideoBase.cpp
@@ -137,8 +137,53 @@ PyObject *Video_getStatus(PyImage *self, void *closure)
}
// refresh video
-PyObject *Video_refresh(PyImage *self)
+PyObject *Video_refresh(PyImage *self, PyObject *args)
{
+ Py_buffer buffer;
+ char *mode = NULL;
+ unsigned int format;
+ double ts = -1.0;
+
+ memset(&buffer, 0, sizeof(buffer));
+ if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) {
+ if (buffer.buf) {
+ // a target buffer is provided, verify its format
+ if (buffer.readonly) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable");
+ }
+ else if (!PyBuffer_IsContiguous(&buffer, 'C')) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory");
+ }
+ else if (((intptr_t)buffer.buf & 3) != 0) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary");
+ }
+ else {
+ // ready to get the image into our buffer
+ try {
+ if (mode == NULL || !strcmp(mode, "RGBA"))
+ format = GL_RGBA;
+ else if (!strcmp(mode, "BGRA"))
+ format = GL_BGRA;
+ else
+ THRWEXCP(InvalidImageMode,S_OK);
+
+ if (!self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts)) {
+ PyErr_SetString(PyExc_TypeError, "Could not load the buffer, perhaps size is not compatible");
+ }
+ }
+ catch (Exception & exp) {
+ exp.report();
+ }
+ }
+ PyBuffer_Release(&buffer);
+ if (PyErr_Occurred())
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
getVideo(self)->refresh();
return Video_getStatus(self, NULL);
}
diff --git a/source/gameengine/VideoTexture/VideoBase.h b/source/gameengine/VideoTexture/VideoBase.h
index 6f35c474300..77f46fdccd8 100644
--- a/source/gameengine/VideoTexture/VideoBase.h
+++ b/source/gameengine/VideoTexture/VideoBase.h
@@ -190,7 +190,7 @@ void Video_open(VideoBase *self, char *file, short captureID);
PyObject *Video_play(PyImage *self);
PyObject *Video_pause(PyImage *self);
PyObject *Video_stop(PyImage *self);
-PyObject *Video_refresh(PyImage *self);
+PyObject *Video_refresh(PyImage *self, PyObject *args);
PyObject *Video_getStatus(PyImage *self, void *closure);
PyObject *Video_getRange(PyImage *self, void *closure);
int Video_setRange(PyImage *self, PyObject *value, void *closure);
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
new file mode 100644
index 00000000000..4f5e34896fc
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -0,0 +1,1228 @@
+/*
+ * ***** 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 gameengine/VideoTexture/VideoDeckLink.cpp
+ * \ingroup bgevideotex
+ */
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+// FFmpeg defines its own version of stdint.h on Windows.
+// Decklink needs FFmpeg, so it uses its version of stdint.h
+// this is necessary for INT64_C macro
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+// this is necessary for UINTPTR_MAX (used by atomic-ops)
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#ifdef __STDC_LIMIT_MACROS /* else it may be unused */
+#endif
+#endif
+#include <stdint.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#endif
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+#include "VideoDeckLink.h"
+#include "DeckLink.h"
+#include "Exception.h"
+#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h"
+
+extern ExceptionID DeckLinkInternalError;
+ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError;
+ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture");
+ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]");
+ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed");
+ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report");
+ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory");
+
+
+#ifdef WIN32
+////////////////////////////////////////////
+// SynInfo
+//
+// Sets up a semaphore which is shared between the GPU and CPU and used to
+// synchronise access to DVP buffers.
+#define DVP_CHECK(cmd) if ((cmd) != DVP_STATUS_OK) THRWEXCP(VideoDeckLinkDvpInternalError, S_OK)
+
+struct SyncInfo
+{
+ SyncInfo(uint32_t semaphoreAllocSize, uint32_t semaphoreAddrAlignment)
+ {
+ mSemUnaligned = (uint32_t*)malloc(semaphoreAllocSize + semaphoreAddrAlignment - 1);
+
+ // Apply alignment constraints
+ uint64_t val = (uint64_t)mSemUnaligned;
+ val += semaphoreAddrAlignment - 1;
+ val &= ~((uint64_t)semaphoreAddrAlignment - 1);
+ mSem = (uint32_t*)val;
+
+ // Initialise
+ mSem[0] = 0;
+ mReleaseValue = 0;
+ mAcquireValue = 0;
+
+ // Setup DVP sync object and import it
+ DVPSyncObjectDesc syncObjectDesc;
+ syncObjectDesc.externalClientWaitFunc = NULL;
+ syncObjectDesc.sem = (uint32_t*)mSem;
+
+ DVP_CHECK(dvpImportSyncObject(&syncObjectDesc, &mDvpSync));
+
+ }
+ ~SyncInfo()
+ {
+ dvpFreeSyncObject(mDvpSync);
+ free((void*)mSemUnaligned);
+ }
+
+ volatile uint32_t* mSem;
+ volatile uint32_t* mSemUnaligned;
+ volatile uint32_t mReleaseValue;
+ volatile uint32_t mAcquireValue;
+ DVPSyncObjectHandle mDvpSync;
+};
+
+////////////////////////////////////////////
+// TextureTransferDvp: transfer with GPUDirect
+////////////////////////////////////////////
+
+class TextureTransferDvp : public TextureTransfer
+{
+public:
+ TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
+ {
+ DVPSysmemBufferDesc sysMemBuffersDesc;
+
+ mExtSync = NULL;
+ mGpuSync = NULL;
+ mDvpSysMemHandle = 0;
+ mDvpTextureHandle = 0;
+ mTextureHeight = 0;
+ mAllocatedSize = 0;
+ mBuffer = NULL;
+
+ if (!_PinBuffer(address, allocatedSize))
+ THRWEXCP(VideoDeckLinkPinMemoryError, S_OK);
+ mAllocatedSize = allocatedSize;
+ mBuffer = address;
+
+ try {
+ if (!mBufferAddrAlignment) {
+ DVP_CHECK(dvpGetRequiredConstantsGLCtx(&mBufferAddrAlignment, &mBufferGpuStrideAlignment,
+ &mSemaphoreAddrAlignment, &mSemaphoreAllocSize,
+ &mSemaphorePayloadOffset, &mSemaphorePayloadSize));
+ }
+ mExtSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
+ mGpuSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
+ sysMemBuffersDesc.width = pDesc->width;
+ sysMemBuffersDesc.height = pDesc->height;
+ sysMemBuffersDesc.stride = pDesc->stride;
+ switch (pDesc->format) {
+ case GL_RED_INTEGER:
+ sysMemBuffersDesc.format = DVP_RED_INTEGER;
+ break;
+ default:
+ sysMemBuffersDesc.format = DVP_BGRA;
+ break;
+ }
+ switch (pDesc->type) {
+ case GL_UNSIGNED_BYTE:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_BYTE;
+ break;
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_8_8_8_8;
+ break;
+ case GL_UNSIGNED_INT_10_10_10_2:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_10_10_10_2;
+ break;
+ default:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT;
+ break;
+ }
+ sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4;
+ sysMemBuffersDesc.bufAddr = mBuffer;
+ DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle));
+ DVP_CHECK(dvpBindToGLCtx(mDvpSysMemHandle));
+ mDvpTextureHandle = dvpTextureHandle;
+ mTextureHeight = pDesc->height;
+ }
+ catch (Exception &) {
+ clean();
+ throw;
+ }
+ }
+ ~TextureTransferDvp()
+ {
+ clean();
+ }
+
+ virtual void PerformTransfer()
+ {
+ // perform the transfer
+ // tell DVP that the old texture buffer will no longer be used
+ dvpMapBufferEndAPI(mDvpTextureHandle);
+ // do we need this?
+ mGpuSync->mReleaseValue++;
+ dvpBegin();
+ // Copy from system memory to GPU texture
+ dvpMapBufferWaitDVP(mDvpTextureHandle);
+ dvpMemcpyLined(mDvpSysMemHandle, mExtSync->mDvpSync, mExtSync->mAcquireValue, DVP_TIMEOUT_IGNORED,
+ mDvpTextureHandle, mGpuSync->mDvpSync, mGpuSync->mReleaseValue, 0, mTextureHeight);
+ dvpMapBufferEndDVP(mDvpTextureHandle);
+ dvpEnd();
+ dvpMapBufferWaitAPI(mDvpTextureHandle);
+ // the transfer is now complete and the texture is ready for use
+ }
+
+private:
+ static uint32_t mBufferAddrAlignment;
+ static uint32_t mBufferGpuStrideAlignment;
+ static uint32_t mSemaphoreAddrAlignment;
+ static uint32_t mSemaphoreAllocSize;
+ static uint32_t mSemaphorePayloadOffset;
+ static uint32_t mSemaphorePayloadSize;
+
+ void clean()
+ {
+ if (mDvpSysMemHandle) {
+ dvpUnbindFromGLCtx(mDvpSysMemHandle);
+ dvpDestroyBuffer(mDvpSysMemHandle);
+ }
+ if (mExtSync)
+ delete mExtSync;
+ if (mGpuSync)
+ delete mGpuSync;
+ if (mBuffer)
+ _UnpinBuffer(mBuffer, mAllocatedSize);
+ }
+ SyncInfo* mExtSync;
+ SyncInfo* mGpuSync;
+ DVPBufferHandle mDvpSysMemHandle;
+ DVPBufferHandle mDvpTextureHandle;
+ uint32_t mTextureHeight;
+ uint32_t mAllocatedSize;
+ void* mBuffer;
+};
+
+uint32_t TextureTransferDvp::mBufferAddrAlignment;
+uint32_t TextureTransferDvp::mBufferGpuStrideAlignment;
+uint32_t TextureTransferDvp::mSemaphoreAddrAlignment;
+uint32_t TextureTransferDvp::mSemaphoreAllocSize;
+uint32_t TextureTransferDvp::mSemaphorePayloadOffset;
+uint32_t TextureTransferDvp::mSemaphorePayloadSize;
+
+#endif
+
+////////////////////////////////////////////
+// TextureTransferOGL: transfer using standard OGL buffers
+////////////////////////////////////////////
+
+class TextureTransferOGL : public TextureTransfer
+{
+public:
+ TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address)
+ {
+ memcpy(&mDesc, pDesc, sizeof(mDesc));
+ mTexId = texId;
+ mBuffer = address;
+
+ // as we cache transfer object, we will create one texture to hold the buffer
+ glGenBuffers(1, &mUnpinnedTextureBuffer);
+ // create a storage for it
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+ ~TextureTransferOGL()
+ {
+ glDeleteBuffers(1, &mUnpinnedTextureBuffer);
+ }
+
+ virtual void PerformTransfer()
+ {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+ glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer);
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+private:
+ // intermediate texture to receive the buffer
+ GLuint mUnpinnedTextureBuffer;
+ // target texture to receive the image
+ GLuint mTexId;
+ // buffer
+ void *mBuffer;
+ // characteristic of the image
+ TextureDesc mDesc;
+};
+
+////////////////////////////////////////////
+// TextureTransferPMB: transfer using pinned memory buffer
+////////////////////////////////////////////
+
+class TextureTransferPMD : public TextureTransfer
+{
+public:
+ TextureTransferPMD(GLuint texId, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
+ {
+ memcpy(&mDesc, pDesc, sizeof(mDesc));
+ mTexId = texId;
+ mBuffer = address;
+ mAllocatedSize = allocatedSize;
+
+ _PinBuffer(address, allocatedSize);
+
+ // as we cache transfer object, we will create one texture to hold the buffer
+ glGenBuffers(1, &mPinnedTextureBuffer);
+ // create a storage for it
+ glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, mPinnedTextureBuffer);
+ glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, pDesc->size, address, GL_STREAM_DRAW);
+ glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
+ }
+ ~TextureTransferPMD()
+ {
+ glDeleteBuffers(1, &mPinnedTextureBuffer);
+ if (mBuffer)
+ _UnpinBuffer(mBuffer, mAllocatedSize);
+ }
+
+ virtual void PerformTransfer()
+ {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPinnedTextureBuffer);
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
+ // wait for the trasnfer to complete
+ GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 40 * 1000 * 1000); // timeout in nanosec
+ glDeleteSync(fence);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+private:
+ // intermediate texture to receive the buffer
+ GLuint mPinnedTextureBuffer;
+ // target texture to receive the image
+ GLuint mTexId;
+ // buffer
+ void *mBuffer;
+ // the allocated size
+ uint32_t mAllocatedSize;
+ // characteristic of the image
+ TextureDesc mDesc;
+};
+
+bool TextureTransfer::_PinBuffer(void *address, uint32_t size)
+{
+#ifdef WIN32
+ return VirtualLock(address, size);
+#elif defined(_POSIX_MEMLOCK_RANGE)
+ return !mlock(address, size);
+#endif
+}
+
+void TextureTransfer::_UnpinBuffer(void* address, uint32_t size)
+{
+#ifdef WIN32
+ VirtualUnlock(address, size);
+#elif defined(_POSIX_MEMLOCK_RANGE)
+ munlock(address, size);
+#endif
+}
+
+
+
+////////////////////////////////////////////
+// PinnedMemoryAllocator
+////////////////////////////////////////////
+
+
+// static members
+bool PinnedMemoryAllocator::mGPUDirectInitialized = false;
+bool PinnedMemoryAllocator::mHasDvp = false;
+bool PinnedMemoryAllocator::mHasAMDPinnedMemory = false;
+size_t PinnedMemoryAllocator::mReservedProcessMemory = 0;
+
+bool PinnedMemoryAllocator::ReserveMemory(size_t size)
+{
+#ifdef WIN32
+ // Increase the process working set size to allow pinning of memory.
+ if (size <= mReservedProcessMemory)
+ return true;
+ SIZE_T dwMin = 0, dwMax = 0;
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId());
+ if (!hProcess)
+ return false;
+
+ // Retrieve the working set size of the process.
+ if (!dwMin && !GetProcessWorkingSetSize(hProcess, &dwMin, &dwMax))
+ return false;
+
+ BOOL res = SetProcessWorkingSetSize(hProcess, (size - mReservedProcessMemory) + dwMin, (size - mReservedProcessMemory) + dwMax);
+ if (!res)
+ return false;
+ mReservedProcessMemory = size;
+ CloseHandle(hProcess);
+ return true;
+#else
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
+ if (rlim.rlim_cur < size) {
+ if (rlim.rlim_max < size)
+ rlim.rlim_max = size;
+ rlim.rlim_cur = size;
+ return !setrlimit(RLIMIT_MEMLOCK, &rlim);
+ }
+ }
+ return false;
+#endif
+}
+
+PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) :
+mRefCount(1U),
+#ifdef WIN32
+mDvpCaptureTextureHandle(0),
+#endif
+mTexId(0),
+mBufferCacheSize(cacheSize)
+{
+ pthread_mutex_init(&mMutex, NULL);
+ // do it once
+ if (!mGPUDirectInitialized) {
+#ifdef WIN32
+ // In windows, AMD_pinned_memory option is not available,
+ // we must use special DVP API only available for Quadro cards
+ const char* renderer = (const char *)glGetString(GL_RENDERER);
+ mHasDvp = (strstr(renderer, "Quadro") != NULL);
+
+ if (mHasDvp) {
+ // In case the DLL is not in place, don't fail, just fallback on OpenGL
+ if (dvpInitGLContext(DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT) != DVP_STATUS_OK) {
+ printf("Warning: Could not initialize DVP context, fallback on OpenGL transfer.\nInstall dvp.dll to take advantage of nVidia GPUDirect.\n");
+ mHasDvp = false;
+ }
+ }
+#endif
+ if (GLEW_AMD_pinned_memory)
+ mHasAMDPinnedMemory = true;
+
+ mGPUDirectInitialized = true;
+ }
+ if (mHasDvp || mHasAMDPinnedMemory) {
+ ReserveMemory(memSize);
+ }
+}
+
+PinnedMemoryAllocator::~PinnedMemoryAllocator()
+{
+ void *address;
+ // first clean the cache if not already done
+ while (!mBufferCache.empty()) {
+ address = mBufferCache.back();
+ mBufferCache.pop_back();
+ _ReleaseBuffer(address);
+ }
+ // clean preallocated buffers
+ while (!mAllocatedSize.empty()) {
+ address = mAllocatedSize.begin()->first;
+ _ReleaseBuffer(address);
+ }
+
+#ifdef WIN32
+ if (mDvpCaptureTextureHandle)
+ dvpDestroyBuffer(mDvpCaptureTextureHandle);
+#endif
+}
+
+void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId)
+{
+ uint32_t allocatedSize = 0;
+ TextureTransfer *pTransfer = NULL;
+
+ Lock();
+ if (mAllocatedSize.count(address) > 0)
+ allocatedSize = mAllocatedSize[address];
+ Unlock();
+ if (!allocatedSize)
+ // internal error!!
+ return;
+ if (mTexId != texId)
+ {
+ // first time we try to send data to the GPU, allocate a buffer for the texture
+ glBindTexture(GL_TEXTURE_2D, texId);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexImage2D(GL_TEXTURE_2D, 0, texDesc->internalFormat, texDesc->width, texDesc->height, 0, texDesc->format, texDesc->type, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ mTexId = texId;
+ }
+#ifdef WIN32
+ if (mHasDvp)
+ {
+ if (!mDvpCaptureTextureHandle)
+ {
+ // bind DVP to the OGL texture
+ DVP_CHECK(dvpCreateGPUTextureGL(texId, &mDvpCaptureTextureHandle));
+ }
+ }
+#endif
+ Lock();
+ if (mPinnedBuffer.count(address) > 0)
+ {
+ pTransfer = mPinnedBuffer[address];
+ }
+ Unlock();
+ if (!pTransfer)
+ {
+#ifdef WIN32
+ if (mHasDvp)
+ pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize);
+ else
+#endif
+ if (mHasAMDPinnedMemory) {
+ pTransfer = new TextureTransferPMD(texId, texDesc, address, allocatedSize);
+ }
+ else {
+ pTransfer = new TextureTransferOGL(texId, texDesc, address);
+ }
+ if (pTransfer)
+ {
+ Lock();
+ mPinnedBuffer[address] = pTransfer;
+ Unlock();
+ }
+ }
+ if (pTransfer)
+ pTransfer->PerformTransfer();
+}
+
+// IUnknown methods
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, LPVOID* /*ppv*/)
+{
+ return E_NOTIMPL;
+}
+
+ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
+{
+ return atomic_add_uint32(&mRefCount, 1U);
+}
+
+ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
+{
+ uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
+ if (newCount == 0)
+ delete this;
+ return (ULONG)newCount;
+}
+
+// IDeckLinkMemoryAllocator methods
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer)
+{
+ Lock();
+ if (mBufferCache.empty())
+ {
+ // Allocate memory on a page boundary
+ // Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then.
+ // Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3
+ // because we don't need any caching
+ if (mAllocatedSize.size() >= mBufferCacheSize)
+ *allocatedBuffer = NULL;
+ else {
+#ifdef WIN32
+ *allocatedBuffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE);
+#else
+ if (posix_memalign(allocatedBuffer, 4096, bufferSize) != 0)
+ *allocatedBuffer = NULL;
+#endif
+ mAllocatedSize[*allocatedBuffer] = bufferSize;
+ }
+ }
+ else {
+ // Re-use most recently ReleaseBuffer'd address
+ *allocatedBuffer = mBufferCache.back();
+ mBufferCache.pop_back();
+ }
+ Unlock();
+ return (*allocatedBuffer) ? S_OK : E_OUTOFMEMORY;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer)
+{
+ HRESULT result = S_OK;
+ Lock();
+ if (mBufferCache.size() < mBufferCacheSize) {
+ mBufferCache.push_back(buffer);
+ }
+ else {
+ result = _ReleaseBuffer(buffer);
+ }
+ Unlock();
+ return result;
+}
+
+
+HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer)
+{
+ TextureTransfer *pTransfer;
+ if (mAllocatedSize.count(buffer) == 0) {
+ // Internal error!!
+ return S_OK;
+ }
+ else {
+ // No room left in cache, so un-pin (if it was pinned) and free this buffer
+ if (mPinnedBuffer.count(buffer) > 0) {
+ pTransfer = mPinnedBuffer[buffer];
+ mPinnedBuffer.erase(buffer);
+ delete pTransfer;
+ }
+#ifdef WIN32
+ VirtualFree(buffer, 0, MEM_RELEASE);
+#else
+ free(buffer);
+#endif
+ mAllocatedSize.erase(buffer);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Commit()
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Decommit()
+{
+ void *buffer;
+ Lock();
+ while (!mBufferCache.empty()) {
+ // Cleanup any frames allocated and pinned in AllocateBuffer() but not freed in ReleaseBuffer()
+ buffer = mBufferCache.back();
+ mBufferCache.pop_back();
+ _ReleaseBuffer(buffer);
+ }
+ Unlock();
+ return S_OK;
+}
+
+
+////////////////////////////////////////////
+// Capture Delegate Class
+////////////////////////////////////////////
+
+CaptureDelegate::CaptureDelegate(VideoDeckLink* pOwner) : mpOwner(pOwner)
+{
+}
+
+HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket* /*audioPacket*/)
+{
+ if (!inputFrame) {
+ // It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame.
+ return S_OK;
+ }
+ if ((inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource) {
+ // let's not bother transferring frames if there is no source
+ return S_OK;
+ }
+ mpOwner->VideoFrameArrived(inputFrame);
+ return S_OK;
+}
+
+HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags)
+{
+ return S_OK;
+}
+
+
+
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); m_status = SourceError; }
+
+// class VideoDeckLink
+
+
+// constructor
+VideoDeckLink::VideoDeckLink (HRESULT * hRslt) : VideoBase(),
+mDLInput(NULL),
+mUse3D(false),
+mFrameWidth(0),
+mFrameHeight(0),
+mpAllocator(NULL),
+mpCaptureDelegate(NULL),
+mpCacheFrame(NULL),
+mClosing(false)
+{
+ mDisplayMode = (BMDDisplayMode)0;
+ mPixelFormat = (BMDPixelFormat)0;
+ pthread_mutex_init(&mCacheMutex, NULL);
+}
+
+// destructor
+VideoDeckLink::~VideoDeckLink ()
+{
+ LockCache();
+ mClosing = true;
+ if (mpCacheFrame)
+ {
+ mpCacheFrame->Release();
+ mpCacheFrame = NULL;
+ }
+ UnlockCache();
+ if (mDLInput != NULL)
+ {
+ // Cleanup for Capture
+ mDLInput->StopStreams();
+ mDLInput->SetCallback(NULL);
+ mDLInput->DisableVideoInput();
+ mDLInput->DisableAudioInput();
+ mDLInput->FlushStreams();
+ if (mDLInput->Release() != 0) {
+ printf("Reference count not NULL on DeckLink device when closing it, please report!\n");
+ }
+ mDLInput = NULL;
+ }
+
+ if (mpAllocator)
+ {
+ // if the device was properly cleared, this should be 0
+ if (mpAllocator->Release() != 0) {
+ printf("Reference count not NULL on Allocator when closing it, please report!\n");
+ }
+ mpAllocator = NULL;
+ }
+ if (mpCaptureDelegate)
+ {
+ delete mpCaptureDelegate;
+ mpCaptureDelegate = NULL;
+ }
+}
+
+void VideoDeckLink::refresh(void)
+{
+ m_avail = false;
+}
+
+// release components
+bool VideoDeckLink::release()
+{
+ // release
+ return true;
+}
+
+// open video file
+void VideoDeckLink::openFile (char *filename)
+{
+ // only live capture on this device
+ THRWEXCP(SourceVideoOnlyCapture, S_OK);
+}
+
+
+// open video capture device
+void VideoDeckLink::openCam (char *format, short camIdx)
+{
+ IDeckLinkDisplayModeIterator* pDLDisplayModeIterator;
+ BMDDisplayModeSupport modeSupport;
+ IDeckLinkDisplayMode* pDLDisplayMode;
+ IDeckLinkIterator* pIterator;
+ BMDTimeValue frameDuration;
+ BMDTimeScale frameTimescale;
+ IDeckLink* pDL;
+ uint32_t displayFlags, inputFlags;
+ char *pPixel, *p3D, *pEnd, *pSize;
+ size_t len;
+ int i, modeIdx, cacheSize;
+
+ // format is constructed as <displayMode>/<pixelFormat>[/3D][:<cacheSize>]
+ // <displayMode> takes the form of BMDDisplayMode identifier minus the 'bmdMode' prefix.
+ // This implementation understands all the modes defined in SDK 10.3.1 but you can alternatively
+ // use the 4 characters internal representation of the mode (e.g. 'HD1080p24' == '24ps')
+ // <pixelFormat> takes the form of BMDPixelFormat identifier minus the 'bmdFormat' prefix.
+ // This implementation understand all the formats defined in SDK 10.32.1 but you can alternatively
+ // use the 4 characters internal representation of the format (e.g. '10BitRGB' == 'r210')
+ // Not all combinations of mode and pixel format are possible and it also depends on the card!
+ // Use /3D postfix if you are capturing a 3D stream with frame packing
+ // Example: To capture FullHD 1920x1080@24Hz with 3D packing and 4:4:4 10 bits RGB pixel format, use
+ // "HD1080p24/10BitRGB/3D" (same as "24ps/r210/3D")
+ // (this will be the normal capture format for FullHD on the DeckLink 4k extreme)
+
+ if ((pSize = strchr(format, ':')) != NULL) {
+ cacheSize = strtol(pSize+1, &pEnd, 10);
+ }
+ else {
+ cacheSize = 8;
+ pSize = format + strlen(format);
+ }
+ if ((pPixel = strchr(format, '/')) == NULL ||
+ ((p3D = strchr(pPixel + 1, '/')) != NULL && strncmp(p3D, "/3D", pSize-p3D)))
+ THRWEXCP(VideoDeckLinkBadFormat, S_OK);
+ mUse3D = (p3D) ? true : false;
+ // to simplify pixel format parsing
+ if (!p3D)
+ p3D = pSize;
+
+ // read the mode
+ len = (size_t)(pPixel - format);
+ // accept integer display mode
+
+ try {
+ // throws if bad mode
+ decklink_ReadDisplayMode(format, len, &mDisplayMode);
+ // found a valid mode, remember that we do not look for an index
+ modeIdx = -1;
+ }
+ catch (Exception &) {
+ // accept also purely numerical mode as a mode index
+ modeIdx = strtol(format, &pEnd, 10);
+ if (pEnd != pPixel || modeIdx < 0)
+ // not a pure number, give up
+ throw;
+ }
+
+ // skip /
+ pPixel++;
+ len = (size_t)(p3D - pPixel);
+ // throws if bad format
+ decklink_ReadPixelFormat(pPixel, len, &mPixelFormat);
+
+ // Caution: DeckLink API used from this point, make sure entity are released before throwing
+ // open the card
+ pIterator = BMD_CreateDeckLinkIterator();
+ if (pIterator) {
+ i = 0;
+ while (pIterator->Next(&pDL) == S_OK) {
+ if (i == camIdx) {
+ if (pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) != S_OK)
+ mDLInput = NULL;
+ pDL->Release();
+ break;
+ }
+ i++;
+ pDL->Release();
+ }
+ pIterator->Release();
+ }
+ if (!mDLInput)
+ THRWEXCP(VideoDeckLinkOpenCard, S_OK);
+
+
+ // check if display mode and pixel format are supported
+ if (mDLInput->GetDisplayModeIterator(&pDLDisplayModeIterator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ pDLDisplayMode = NULL;
+ displayFlags = (mUse3D) ? bmdDisplayModeSupports3D : 0;
+ inputFlags = (mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault;
+ while (pDLDisplayModeIterator->Next(&pDLDisplayMode) == S_OK)
+ {
+ if (modeIdx == 0 || pDLDisplayMode->GetDisplayMode() == mDisplayMode) {
+ // in case we get here because of modeIdx, make sure we have mDisplayMode set
+ mDisplayMode = pDLDisplayMode->GetDisplayMode();
+ if ((pDLDisplayMode->GetFlags() & displayFlags) == displayFlags &&
+ mDLInput->DoesSupportVideoMode(mDisplayMode, mPixelFormat, inputFlags, &modeSupport, NULL) == S_OK &&
+ modeSupport == bmdDisplayModeSupported)
+ {
+ break;
+ }
+ }
+ pDLDisplayMode->Release();
+ pDLDisplayMode = NULL;
+ if (modeIdx-- == 0) {
+ // reached the correct mode index but it does not meet the pixel format, give up
+ break;
+ }
+ }
+ pDLDisplayModeIterator->Release();
+
+ if (pDLDisplayMode == NULL)
+ THRWEXCP(VideoDeckLinkBadFormat, S_OK);
+
+ mFrameWidth = pDLDisplayMode->GetWidth();
+ mFrameHeight = pDLDisplayMode->GetHeight();
+ mTextureDesc.height = (mUse3D) ? 2 * mFrameHeight : mFrameHeight;
+ pDLDisplayMode->GetFrameRate(&frameDuration, &frameTimescale);
+ pDLDisplayMode->Release();
+ // for information, in case the application wants to know
+ m_size[0] = mFrameWidth;
+ m_size[1] = mTextureDesc.height;
+ m_frameRate = (float)frameTimescale / (float)frameDuration;
+
+ switch (mPixelFormat)
+ {
+ case bmdFormat8BitYUV:
+ // 2 pixels per word
+ mTextureDesc.stride = mFrameWidth * 2;
+ mTextureDesc.width = mFrameWidth / 2;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_BYTE;
+ break;
+ case bmdFormat10BitYUV:
+ // 6 pixels in 4 words, rounded to 48 pixels
+ mTextureDesc.stride = ((mFrameWidth + 47) / 48) * 128;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_RGB10_A2;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+ case bmdFormat8BitARGB:
+ mTextureDesc.stride = mFrameWidth * 4;
+ mTextureDesc.width = mFrameWidth;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_INT_8_8_8_8;
+ break;
+ case bmdFormat8BitBGRA:
+ mTextureDesc.stride = mFrameWidth * 4;
+ mTextureDesc.width = mFrameWidth;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_BYTE;
+ break;
+ case bmdFormat10BitRGBXLE:
+ // 1 pixel per word, rounded to 64 pixels
+ mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_RGB10_A2;
+ mTextureDesc.format = GL_RGBA;
+ mTextureDesc.type = GL_UNSIGNED_INT_10_10_10_2;
+ break;
+ case bmdFormat10BitRGBX:
+ case bmdFormat10BitRGB:
+ // 1 pixel per word, rounded to 64 pixels
+ mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_R32UI;
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ case bmdFormat12BitRGB:
+ case bmdFormat12BitRGBLE:
+ // 8 pixels in 9 word
+ mTextureDesc.stride = (mFrameWidth * 36) / 8;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_R32UI;
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ default:
+ // for unknown pixel format, this will be resolved when a frame arrives
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ }
+ // reserve memory for cache frame + 1 to accomodate for pixel format that we don't know yet
+ // note: we can't use stride as it is not yet known if the pixel format is unknown
+ // use instead the frame width as in worst case it's not much different (e.g. HD720/10BITYUV: 1296 pixels versus 1280)
+ // note: some pixel format take more than 4 bytes take that into account (9/8 versus 1)
+ mpAllocator = new PinnedMemoryAllocator(cacheSize, mFrameWidth*mTextureDesc.height * 4 * (1+cacheSize*9/8));
+
+ if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ mpCaptureDelegate = new CaptureDelegate(this);
+ if (mDLInput->SetCallback(mpCaptureDelegate) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ if (mDLInput->EnableVideoInput(mDisplayMode, mPixelFormat, ((mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault)) != S_OK)
+ // this shouldn't failed, we tested above
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ // just in case it is needed to capture from certain cards, we don't check error because we don't need audio
+ mDLInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2);
+
+ // open base class
+ VideoBase::openCam(format, camIdx);
+
+ // ready to capture, will start when application calls play()
+}
+
+// play video
+bool VideoDeckLink::play (void)
+{
+ try
+ {
+ // if object is able to play
+ if (VideoBase::play())
+ {
+ mDLInput->FlushStreams();
+ return (mDLInput->StartStreams() == S_OK);
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// pause video
+bool VideoDeckLink::pause (void)
+{
+ try
+ {
+ if (VideoBase::pause())
+ {
+ mDLInput->PauseStreams();
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+// stop video
+bool VideoDeckLink::stop (void)
+{
+ try
+ {
+ VideoBase::stop();
+ mDLInput->StopStreams();
+ return true;
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// set video range
+void VideoDeckLink::setRange (double start, double stop)
+{
+}
+
+// set framerate
+void VideoDeckLink::setFrameRate (float rate)
+{
+}
+
+
+// image calculation
+// send cache frame directly to GPU
+void VideoDeckLink::calcImage (unsigned int texId, double ts)
+{
+ IDeckLinkVideoInputFrame* pFrame;
+ LockCache();
+ pFrame = mpCacheFrame;
+ mpCacheFrame = NULL;
+ UnlockCache();
+ if (pFrame) {
+ // BUG: the dvpBindToGLCtx function fails the first time it is used, don't know why.
+ // This causes an exception to be thrown.
+ // This should be fixed but in the meantime we will catch the exception because
+ // it is crucial that we release the frame to keep the reference count right on the DeckLink device
+ try {
+ uint32_t rowSize = pFrame->GetRowBytes();
+ uint32_t textureSize = rowSize * pFrame->GetHeight();
+ void* videoPixels = NULL;
+ void* rightEyePixels = NULL;
+ if (!mTextureDesc.stride) {
+ // we could not compute the texture size earlier (unknown pixel size)
+ // let's do it now
+ mTextureDesc.stride = rowSize;
+ mTextureDesc.width = mTextureDesc.stride / 4;
+ }
+ if (mTextureDesc.stride != rowSize) {
+ // unexpected frame size, ignore
+ // TBD: print a warning
+ }
+ else {
+ pFrame->GetBytes(&videoPixels);
+ if (mUse3D) {
+ IDeckLinkVideoFrame3DExtensions *if3DExtensions = NULL;
+ IDeckLinkVideoFrame *rightEyeFrame = NULL;
+ if (pFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **)&if3DExtensions) == S_OK &&
+ if3DExtensions->GetFrameForRightEye(&rightEyeFrame) == S_OK) {
+ rightEyeFrame->GetBytes(&rightEyePixels);
+ textureSize += ((uint64_t)rightEyePixels - (uint64_t)videoPixels);
+ }
+ if (rightEyeFrame)
+ rightEyeFrame->Release();
+ if (if3DExtensions)
+ if3DExtensions->Release();
+ }
+ mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4;
+ if (mTextureDesc.size == textureSize) {
+ // this means that both left and right frame are contiguous and that there is no padding
+ // do the transfer
+ mpAllocator->TransferBuffer(videoPixels, &mTextureDesc, texId);
+ }
+ }
+ }
+ catch (Exception &) {
+ pFrame->Release();
+ throw;
+ }
+ // this will trigger PinnedMemoryAllocator::RealaseBuffer
+ pFrame->Release();
+ }
+ // currently we don't pass the image to the application
+ m_avail = false;
+}
+
+// A frame is available from the board
+// Called from an internal thread, just pass the frame to the main thread
+void VideoDeckLink::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame)
+{
+ IDeckLinkVideoInputFrame* pOldFrame = NULL;
+ LockCache();
+ if (!mClosing)
+ {
+ pOldFrame = mpCacheFrame;
+ mpCacheFrame = inputFrame;
+ inputFrame->AddRef();
+ }
+ UnlockCache();
+ // old frame no longer needed, just release it
+ if (pOldFrame)
+ pOldFrame->Release();
+}
+
+// python methods
+
+// object initialization
+static int VideoDeckLink_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = { "format", "capture", NULL };
+ PyImage *self = reinterpret_cast<PyImage*>(pySelf);
+ // see openCam for a description of format
+ char * format = NULL;
+ // capture device number, i.e. DeckLink card number, default first one
+ short capt = 0;
+
+ if (!GLEW_VERSION_1_5) {
+ PyErr_SetString(PyExc_RuntimeError, "VideoDeckLink requires at least OpenGL 1.5");
+ return -1;
+ }
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|h",
+ const_cast<char**>(kwlist), &format, &capt))
+ return -1;
+
+ try {
+ // create video object
+ Video_init<VideoDeckLink>(self);
+
+ // open video source, control comes back to VideoDeckLink::openCam
+ Video_open(getVideo(self), format, capt);
+ }
+ catch (Exception & exp) {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+// methods structure
+static PyMethodDef videoMethods[] =
+{ // methods from VideoBase class
+ {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"},
+ {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"},
+ {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef videoGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
+ {(char*)"framerate", (getter)Video_getFrameRate, NULL, (char*)"frame rate", NULL},
+ // attributes from ImageBase class
+ {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
+ {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
+ {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
+ {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
+ {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+ {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
+ {NULL}
+};
+
+// python type declaration
+PyTypeObject VideoDeckLinkType =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VideoTexture.VideoDeckLink", /*tp_name*/
+ sizeof(PyImage), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Image_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &imageBufferProcs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "DeckLink video source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ videoMethods, /* tp_methods */
+ 0, /* tp_members */
+ videoGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VideoDeckLink_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+
+
+////////////////////////////////////////////
+// DeckLink Capture Delegate Class
+////////////////////////////////////////////
+
+#endif // WITH_GAMEENGINE_DECKLINK
+
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h
new file mode 100644
index 00000000000..50099d2ead4
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoDeckLink.h
@@ -0,0 +1,256 @@
+/*
+ * ***** 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 VideoDeckLink.h
+ * \ingroup bgevideotex
+ */
+
+#ifndef __VIDEODECKLINK_H__
+#define __VIDEODECKLINK_H__
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+/* this needs to be parsed with __cplusplus defined before included through DeckLink_compat.h */
+#if defined(__FreeBSD__)
+# include <inttypes.h>
+#endif
+#include <map>
+#include <set>
+
+extern "C" {
+#include <pthread.h>
+#include "DNA_listBase.h"
+#include "BLI_threads.h"
+#include "BLI_blenlib.h"
+}
+#include "GL/glew.h"
+#ifdef WIN32
+#include "dvpapi.h"
+#endif
+#include "DeckLinkAPI.h"
+#include "VideoBase.h"
+
+class PinnedMemoryAllocator;
+
+struct TextureDesc
+{
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t size;
+ GLenum internalFormat;
+ GLenum format;
+ GLenum type;
+ TextureDesc()
+ {
+ width = 0;
+ height = 0;
+ stride = 0;
+ size = 0;
+ internalFormat = 0;
+ format = 0;
+ type = 0;
+ }
+};
+
+class CaptureDelegate;
+
+// type VideoDeckLink declaration
+class VideoDeckLink : public VideoBase
+{
+ friend class CaptureDelegate;
+public:
+ /// constructor
+ VideoDeckLink (HRESULT * hRslt);
+ /// destructor
+ virtual ~VideoDeckLink ();
+
+ /// open video/image file
+ virtual void openFile(char *file);
+ /// open video capture device
+ virtual void openCam(char *driver, short camIdx);
+
+ /// release video source
+ virtual bool release (void);
+ /// overwrite base refresh to handle fixed image
+ virtual void refresh(void);
+ /// play video
+ virtual bool play (void);
+ /// pause video
+ virtual bool pause (void);
+ /// stop video
+ virtual bool stop (void);
+ /// set play range
+ virtual void setRange (double start, double stop);
+ /// set frame rate
+ virtual void setFrameRate (float rate);
+
+protected:
+ // format and codec information
+ /// image calculation
+ virtual void calcImage (unsigned int texId, double ts);
+
+private:
+ void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame);
+ void LockCache()
+ {
+ pthread_mutex_lock(&mCacheMutex);
+ }
+ void UnlockCache()
+ {
+ pthread_mutex_unlock(&mCacheMutex);
+ }
+
+ IDeckLinkInput* mDLInput;
+ BMDDisplayMode mDisplayMode;
+ BMDPixelFormat mPixelFormat;
+ bool mUse3D;
+ uint32_t mFrameWidth;
+ uint32_t mFrameHeight;
+ TextureDesc mTextureDesc;
+ PinnedMemoryAllocator* mpAllocator;
+ CaptureDelegate* mpCaptureDelegate;
+
+ // cache frame in transit between the callback thread and the main BGE thread
+ // keep only one frame in cache because we just want to keep up with real time
+ pthread_mutex_t mCacheMutex;
+ IDeckLinkVideoInputFrame* mpCacheFrame;
+ bool mClosing;
+
+};
+
+inline VideoDeckLink *getDeckLink(PyImage *self)
+{
+ return static_cast<VideoDeckLink*>(self->m_image);
+}
+
+////////////////////////////////////////////
+// TextureTransfer : Abstract class to perform a transfer to GPU memory using fast transfer if available
+////////////////////////////////////////////
+class TextureTransfer
+{
+public:
+ TextureTransfer() {}
+ virtual ~TextureTransfer() { }
+
+ virtual void PerformTransfer() = 0;
+protected:
+ static bool _PinBuffer(void *address, uint32_t size);
+ static void _UnpinBuffer(void* address, uint32_t size);
+};
+
+////////////////////////////////////////////
+// PinnedMemoryAllocator
+////////////////////////////////////////////
+
+// PinnedMemoryAllocator implements the IDeckLinkMemoryAllocator interface and can be used instead of the
+// built-in frame allocator, by setting with SetVideoInputFrameMemoryAllocator() or SetVideoOutputFrameMemoryAllocator().
+//
+// For this sample application a custom frame memory allocator is used to ensure each address
+// of frame memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension.
+// If the pinned memory extension is not available, this allocator will still be used and
+// demonstrates how to cache frame allocations for efficiency.
+//
+// The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an
+// allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame.
+
+
+class PinnedMemoryAllocator : public IDeckLinkMemoryAllocator
+{
+public:
+ PinnedMemoryAllocator(unsigned cacheSize, size_t memSize);
+ virtual ~PinnedMemoryAllocator();
+
+ void TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId);
+
+ // IUnknown methods
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IDeckLinkMemoryAllocator methods
+ virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer);
+ virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer);
+ virtual HRESULT STDMETHODCALLTYPE Commit();
+ virtual HRESULT STDMETHODCALLTYPE Decommit();
+
+private:
+ static bool mGPUDirectInitialized;
+ static bool mHasDvp;
+ static bool mHasAMDPinnedMemory;
+ static size_t mReservedProcessMemory;
+ static bool ReserveMemory(size_t size);
+
+ void Lock()
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+ void Unlock()
+ {
+ pthread_mutex_unlock(&mMutex);
+ }
+ HRESULT _ReleaseBuffer(void* buffer);
+
+ uint32_t mRefCount;
+ // protect the cache and the allocated map,
+ // not the pinnedBuffer map as it is only used from main thread
+ pthread_mutex_t mMutex;
+ std::map<void*, uint32_t> mAllocatedSize;
+ std::vector<void*> mBufferCache;
+ std::map<void *, TextureTransfer*> mPinnedBuffer;
+#ifdef WIN32
+ DVPBufferHandle mDvpCaptureTextureHandle;
+#endif
+ // target texture in GPU
+ GLuint mTexId;
+ uint32_t mBufferCacheSize;
+};
+
+////////////////////////////////////////////
+// Capture Delegate Class
+////////////////////////////////////////////
+
+class CaptureDelegate : public IDeckLinkInputCallback
+{
+ VideoDeckLink* mpOwner;
+
+public:
+ CaptureDelegate(VideoDeckLink* pOwner);
+
+ // IUnknown needs only a dummy implementation
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; }
+ virtual ULONG STDMETHODCALLTYPE Release() { return 1; }
+
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket);
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags);
+};
+
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
+
+#endif /* __VIDEODECKLINK_H__ */
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index 5fed1211d6c..083e9e28502 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -1203,7 +1203,7 @@ static PyMethodDef videoMethods[] =
{"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"},
{"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"},
{"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"},
- {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"},
{NULL}
};
// attributes structure
@@ -1326,7 +1326,7 @@ static PyObject *Image_reload(PyImage *self, PyObject *args)
// methods structure
static PyMethodDef imageMethods[] =
{ // methods from VideoBase class
- {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh image, i.e. load it"},
{"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"},
{NULL}
};
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
index a62ffee3137..9b046d46412 100644
--- a/source/gameengine/VideoTexture/blendVideoTex.cpp
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -128,6 +128,10 @@ static PyMethodDef moduleMethods[] =
extern PyTypeObject VideoFFmpegType;
extern PyTypeObject ImageFFmpegType;
#endif
+#ifdef WITH_GAMEENGINE_DECKLINK
+extern PyTypeObject VideoDeckLinkType;
+extern PyTypeObject DeckLinkType;
+#endif
extern PyTypeObject FilterBlueScreenType;
extern PyTypeObject FilterGrayType;
extern PyTypeObject FilterColorType;
@@ -145,6 +149,9 @@ static void registerAllTypes(void)
pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg");
pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg");
#endif
+#ifdef WITH_GAMEENGINE_DECKLINK
+ pyImageTypes.add(&VideoDeckLinkType, "VideoDeckLink");
+#endif
pyImageTypes.add(&ImageBuffType, "ImageBuff");
pyImageTypes.add(&ImageMixType, "ImageMix");
pyImageTypes.add(&ImageRenderType, "ImageRender");
@@ -194,6 +201,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void)
return NULL;
if (PyType_Ready(&TextureType) < 0)
return NULL;
+#ifdef WITH_GAMEENGINE_DECKLINK
+ if (PyType_Ready(&DeckLinkType) < 0)
+ return NULL;
+#endif
m = PyModule_Create(&VideoTexture_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m);
@@ -207,6 +218,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void)
Py_INCREF(&TextureType);
PyModule_AddObject(m, "Texture", (PyObject *)&TextureType);
+#ifdef WITH_GAMEENGINE_DECKLINK
+ Py_INCREF(&DeckLinkType);
+ PyModule_AddObject(m, "DeckLink", (PyObject *)&DeckLinkType);
+#endif
PyModule_AddIntConstant(m, "SOURCE_ERROR", SourceError);
PyModule_AddIntConstant(m, "SOURCE_EMPTY", SourceEmpty);
PyModule_AddIntConstant(m, "SOURCE_READY", SourceReady);